CF1830E Bully Sort

考虑弱化题意,不带修。

模拟一下操作,发现是每次将当前 aiia_i \ne i 的数往后移,且每次移动 i[1,n],iai\forall i\in[1,n],|i-a_i| 单调不增,即点的移动方向是固定的。

当移点 ii 时,数 [ai+1,n][a_i+1,n] 已合法,ii 每次会移动到的点是区间 [i+1,ai][i + 1,a_i] 的后缀 min 等于自己的点,且会交换这些点,记这些点为关键点。

记关键点个数为 jj,则 j\sum j 即为答案。

这个比较难算,但是手玩几组可能会发现,不是关键点的点数跟逆序对有关!

对于将点 ii 移到结尾的操作,逆序对减少了 ww,则 [i+1,ai][i+1,a_i] 中不是关键点的点数为 ww,于是有 j=iaiwj=|i-a_i|-w

记原序列逆序对个数为 ss,则 j=iiais\sum j = \sum\limits_i |i-a_i|-s

再考虑带修,即支持交换两数和询问全局逆序对。

考虑一个数据结构,维护区间中小于或大于一个数的数的个数和交换即可。

分块,典。

时间复杂度为 O(qnlog(n))\mathcal O(q\sqrt{n\log(\sqrt n)})

#include<bits/stdc++.h>
using namespace std;
//#define int long long
#define F(i, a, b) for(int i = a; i <= (b); ++i)
#define F2(i, a, b) for(int i = a; i < (b); ++i)
#define dF(i, a, b) for(int i = a; i >= (b); --i)
#define pb push_back
typedef long long ll;
namespace Fread {const int SIZE = 1 << 18; char buf[SIZE], *S, *T; inline char getchar() {if (S == T) {T = (S = buf) + fread(buf, 1, SIZE, stdin); if (S == T) return '\n';} return *S++;}}
namespace Fwrite {const int SIZE = 1 << 18; char buf[SIZE], *S = buf, *T = buf + SIZE; inline void flush() {fwrite(buf, 1, S - buf, stdout), S = buf;} inline void putchar(char c) {*S++ = c;if (S == T) flush();} struct NTR {~NTR() {flush();}} ztr;}
#ifdef ONLINE_JUDGE
#define getchar Fread::getchar
#define putchar Fwrite::putchar
#endif
inline int ri() {
	int x = 0;
	char c = getchar();
	while (c < '0' || c > '9') c = getchar();
	while (c >= '0' && c <= '9') x = (x << 3) + (x << 1) + (c ^ 48), c = getchar();
	return x;
}
inline void wi(ll x) {
	if (x > 9) wi(x / 10);
	putchar(x % 10 + 48);;
}
inline void wi(ll x, char s) {
	wi(x), putchar(s);
}
const int _ = 5e5 + 5, SQ = 250, M = _ / SQ + 5;
int n, q, a[_], c[_], sq, bel[_], L[M], R[M];
vector<int> v[M];
void upd(int x, int v) {
	for(; x <= n; x += x & -x) c[x] += v;
}
int qry(int x) {
	int r = 0;
	for(; x; x -= x & -x) r += c[x];
	return r;
}
int qry(int l, int r) {
	if(l > r) swap(l, r);
	if(l == r) return 0;
	int l2 = l + 1, r2 = r - 1;
	if(l2 > r2) {
		if(a[l] < a[r]) return 1;
		return -1;
	}
	int res = 0, x = a[r];
	if(bel[l2] == bel[r2]) {
		F(i, l2, r2) if(a[i] > x) res--; else res++;
	} else {
		F(i, l2, R[bel[l2]]) if(a[i] > x) res--; else res++;
		F(i, bel[l2] + 1, bel[r2] - 1) {
			auto w = lower_bound(v[i].begin(), v[i].end(), x);
			int p = w - v[i].begin();
			res -= (R[i] - L[i] + 1) - p;
			res += p;
		}
		F(i, L[bel[r2]], r2) if(a[i] > x) res--; else res++;
	}
	x = a[l];
	if(bel[l2] == bel[r2]) {
		F(i, l2, r2) if(a[i] < x) res--; else res++;
	} else {
		F(i, l2, R[bel[l2]]) if(a[i] < x) res--; else res++;
		F(i, bel[l2] + 1, bel[r2] - 1) {
			auto w = lower_bound(v[i].begin(), v[i].end(), x);
			int p = w - v[i].begin();
			res += (R[i] - L[i] + 1) - p;
			res -= p;
		}
		F(i, L[bel[r2]], r2) if(a[i] < x) res--; else res++;
	}
	if(a[l] < a[r]) res++;
	else res--;
	return res;
}
void del(int x, int y) {
	v[x].erase(lower_bound(v[x].begin(), v[x].end(), y));
}
void add(int x, int y) {
	v[x].insert(lower_bound(v[x].begin(), v[x].end(), y), y);
}
void solve() {
	n = ri(), q = ri();
	sq = sqrt(n * log(n));
	F(i, 1, n) a[i] = ri();
	ll ans = 0;
	F(i, 1, n) ans += abs(i - a[i]);
	F(i, 1, n) {
		ans -= (i - 1) - qry(a[i]);
		upd(a[i], 1);
	}
	F(i, 1, n) bel[i] = (i - 1) / sq + 1, v[bel[i]].pb(a[i]);
	F(i, 1, bel[n]) L[i] = R[i - 1] + 1, R[i] = i * sq; R[bel[n]] = min(R[bel[n]], n);
	F(i, 1, bel[n]) sort(v[i].begin(), v[i].end());
	int x, y;
	F(t, 1, q) {
		x = ri(), y = ri();
		ans -= abs(x - a[x]);
		ans -= abs(y - a[y]);
		ans -= qry(x, y);
		swap(a[x], a[y]);
		ans += abs(x - a[x]);
		ans += abs(y - a[y]);
		wi(ans, '\n');
		if(x != y) {
			del(bel[x], a[y]), add(bel[x], a[x]);
			del(bel[y], a[x]), add(bel[y], a[y]);
		}
	}
}

bool Med;
signed main() {
	//	srand(time(0));
	// Mry;
	solve();
	// Try;
}
posted @ 2023-05-29 20:05  蒟蒻orz  阅读(1)  评论(0编辑  收藏  举报  来源