当前位置 : 主页 > 大数据 > 区块链 >

[CF785E]Anton and Permutation

来源:互联网 收集:自由互联 发布时间:2021-06-22
题目大意: 有一串数为$1\sim n(n\leqslant2\times10^5)$,$m(m\leqslant5\times10^4)$次询问,每次问交换位置为$l,r$的两个数后数列中逆序对的个数。 题解: 发现交换位置为$l,r$的数后,逆序对的变

题目大意:有一串数为$1\sim n(n\leqslant2\times10^5)$,$m(m\leqslant5\times10^4)$次询问,每次问交换位置为$l,r$的两个数后数列中逆序对的个数。

题解:发现交换位置为$l,r$的数后,逆序对的变化只和区间$(l,r)$内的数与$s_l,s_r$的大小关系有关,设$S_i$表示区间$(l,r)$中比$s_i$小的数,$B_i$表示区间$(l,r)$中比$s_i$大的数,$ans‘=ans+S_r-B_r-S_l+B_l$。设$len=r-l-1$,$ans‘=ans+S_r-(len-S_r)-S_l+(len-S_l)=ans+2(S_r-S_l)$。

考虑分块,设块大小为$S$,在块内排序,在边角处暴力,在整块处二分查找位置,询问的复杂度是$O(2S+\dfrac n S\log_2S)$;修改为二分处位置直接插入或删除,复杂度$O(4S)$,所以当$S$略大于$\sqrt n$时最优。(反正我懒得算,随便猜一个)

卡点:

  1. 计算$2(S_r-S_l)$时使用了位运算,当$S_r-S_l$为负数时出锅
  2. 最开始块大小设成了$512$,计算块时用了$2^8$

 

C++ Code:

#include <algorithm>
#include <cstdio>
#include <vector>
#define maxn 200010
const int BSZ = 1000, BNUM = maxn / BSZ + 10;

int n, m;
long long ans;
int L[BNUM], R[BNUM], bel[maxn], s[maxn];
std::vector<int> V[BNUM];

int query(int l, int r, int x) {
	if (l > r) return 0;
	const int lb = bel[l], rb = bel[r];
	int res = 0;
	if (lb == rb) for (int i = l; i <= r; ++i) res += s[i] < x;
	else {
		for (int i = l; i <= R[lb]; ++i) res += s[i] < x;
		for (int i = lb + 1; i < rb; ++i) res += std::upper_bound(V[i].begin(), V[i].end(), x) - V[i].begin();
		for (int i = L[rb]; i <= r; ++i) res += s[i] < x;
	}
	return res;
}

int main() {
	scanf("%d%d", &n, &m);
	for (int i = 1; i <= n; ++i) V[bel[i] = i / BSZ + 1].push_back(s[i] = i);
	const int B = bel[n];
	for (int i = 1; i <= B; ++i) {
		L[i] = (i - 1) * BSZ;
		R[i] = L[i] + BSZ - 1;
	}
	L[1] = 1, R[B] = n;
	while (m --> 0) {
		int l, r;
		scanf("%d%d", &l, &r);
		if (l == r) {
			printf("%lld\n", ans);
			continue;
		}
		if (l > r) std::swap(l, r);
		const int lb = bel[l], rb = bel[r];

		ans += (query(l + 1, r - 1, s[r]) - query(l + 1, r - 1, s[l])) * 2;
		ans += (s[l] < s[r]) ? 1 : -1;
		printf("%lld\n", ans);

		if (lb != rb) {
			V[lb].erase(std::lower_bound(V[lb].begin(), V[lb].end(), s[l]));
			V[lb].insert(std::upper_bound(V[lb].begin(), V[lb].end(), s[r]), s[r]);
			V[rb].erase(std::lower_bound(V[rb].begin(), V[rb].end(), s[r]));
			V[rb].insert(std::upper_bound(V[rb].begin(), V[rb].end(), s[l]), s[l]);
		}
		std::swap(s[l], s[r]);
	}
	return 0;
}
网友评论