bzoj 5301 [Cqoi2018]异或序列 莫队

题面

题目传送门

解法

异或满足前缀相减性,记\(s_i\)\(a_1\ xor\ a_2…xor\ a_i\)

然后就可以直接莫队求解了

注意在移动左端点时统计答案应该为\(l-1\),而不是\(l\)

时间复杂度:\(O(n\sqrt q)\)

代码

#include <bits/stdc++.h>
#define int long long
#define N 100010
using namespace std;
template <typename node> void read(node &x) {
	x = 0; int f = 1; char c = getchar();
	while (!isdigit(c)) {if (c == '-') f = -1; c = getchar();}
	while (isdigit(c)) x = x * 10 + c - '0', c = getchar(); x *= f;
}
struct Node {
	int l, r, id;
} b[N];
int n, q, k, sum, a[N], s[N], ans[N], col[N], cnt[1 << 17];
bool cmp(Node x, Node y) {
	return col[x.l] ^ col[y.l] ? x.l < y.l : col[x.l] & 1 ? x.r < y.r : x.r > y.r;
}
void update(int x, int v) {
	sum += cnt[s[x] ^ k] * v;
	cnt[s[x]] += v;
}
main() {
	read(n), read(q), read(k);
	int siz = n / sqrt(q * 2 / 3);
	for (int i = 1; i <= n; i++)
		read(a[i]), s[i] = s[i - 1] ^ a[i], col[i] = (i + siz - 1) / siz;
	for (int i = 1; i <= q; i++)
		read(b[i].l), read(b[i].r), b[i].id = i;
	sort(b + 1, b + q + 1, cmp); cnt[0] = 1;
	for (int i = 1, l = 1, r = 0; i <= q; i++) {
		while (r < b[i].r) update(++r, 1);
		while (r > b[i].r) update(r--, -1);
		while (l < b[i].l) update(l - 1, -1), l++;
		while (l > b[i].l) l--, update(l - 1, 1);
		ans[b[i].id] = sum;
	}
	for (int i = 1; i <= q; i++) cout << ans[i] << "\n";
	return 0;
}

posted @ 2018-08-14 23:14  谜のNOIP  阅读(88)  评论(0编辑  收藏  举报