P4462 题解

题目传送门

请确保您接触过莫队再阅读此文:

注:下文中的所有 \(\oplus\) 均表示两数按位异或。

对于所有询问,和普通莫队一样的分块然后排序。在这里只讨论 adddel 操作的具体实现。

题目中需要求一段区间的异或值,所以我们可以预处理序列 \(a\) 的“前缀异或值”pre_xor,题目中的 \(a_x \oplus a_{x+1} \oplus \dots \oplus a_y\) 可利用异或的性质转化为 pre_xor[y] ^ pre_xor[x - 1]

这样,求区间 \([l,r]\) 中能够满足 \(a_x \oplus a_{x+1} \oplus \dots \oplus a_y = k\)\(x,y\) 有多少组,就相当于求区间 \([l - 1,r]\) 中有多少组 pre_xor[y] ^ pre_xor[x - 1] == k。这就可以用莫队了。

显然,设 cnt[x] 代表数 \(x\) 的出现次数,则其可以与所有的 \(x \oplus k\) 配对即可。显然,在这里的 \(x\)\(x \oplus k\) 一般是不用担心顺序的,总贡献为 cnt[x] * cnt[x ^ k]

不过有一个特殊情况:当 \(k = 0\) 时,\(x = x \oplus k\),这个时候就得特判贡献为 (cnt[x] * (cnt[x] - 1)) >> 1 了。

#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N = 1e5 + 9,M = 1e5 + 9,SqrtN = 339,K = 1 << 20;
int n,m,k;
struct block{
	int l,r;
} b[SqrtN];
int belong[N];
int block_len,block_cnt;
void build_block(){
	block_len = block_cnt = (int)sqrt(n);
	for(int i = 1;i <= block_cnt;i++){
		b[i].l = b[i - 1].r + 1;
		b[i].r = i * block_len;
	}
	b[block_cnt].r = n;
	for(int i = 1;i <= block_cnt;i++)
		for(int j = b[i].l;j <= b[i].r;j++)
			belong[j] = i;
}
struct queries{
	int l,r,id;
} q[M];
int a[N],pre_xor[N];
int cnt[K];
int ans[M],tmp;
int lres = 1,rres;
bool cmp(queries q1,queries q2){
    return belong[q1.l] == belong[q2.l] ? belong[q1.r] < belong[q2.r] : belong[q1.l] < belong[q2.l];
}
void add(int x){
	//tmp -= cnt[x] * (k ? cnt[x ^ k] : (cnt[x] - 1));
	tmp -= k ? (cnt[x] * cnt[x ^ k]) : ((cnt[x] * (cnt[x] - 1)) >> 1);
	cnt[x]++;
	//tmp += cnt[x] * (k ? cnt[x ^ k] : (cnt[x] - 1));
	tmp += k ? (cnt[x] * cnt[x ^ k]) : ((cnt[x] * (cnt[x] - 1)) >> 1);
}
void del(int x){
	//tmp -= cnt[x] * (k ? cnt[x ^ k] : (cnt[x] - 1));
	tmp -= k ? (cnt[x] * cnt[x ^ k]) : ((cnt[x] * (cnt[x] - 1)) >> 1);
	cnt[x]--;
	//tmp += cnt[x] * (k ? cnt[x ^ k] : (cnt[x] - 1));
	tmp += k ? (cnt[x] * cnt[x ^ k]) : ((cnt[x] * (cnt[x] - 1)) >> 1);
}
signed main(){
	ios::sync_with_stdio(false);
	cin.tie(0);cout.tie(0);
	cin >> n >> m >> k;
	build_block();
	for(int i = 1;i <= n;i++){
		cin >> a[i];
		pre_xor[i] = pre_xor[i - 1] ^ a[i];
	}
	for(int i = 1;i <= m;i++){
		cin >> q[i].l >> q[i].r;
		q[i].id = i;
	}
	sort(q + 1,q + m + 1,cmp);
    for(int i = 1;i <= m;i++){
        int L = q[i].l - 1,R = q[i].r;
        while(lres > L)
            add(pre_xor[--lres]);
        while(rres < R)
            add(pre_xor[++rres]);
        while(lres < L)
            del(pre_xor[lres++]);
        while(rres > R)
            del(pre_xor[rres--]);
        ans[q[i].id] = tmp;
    }
	for(int i = 1;i <= m;i++)
		cout << ans[i] << '\n';
	return 0;
}
posted @ 2024-04-08 13:12  5t0_0r2  阅读(11)  评论(0编辑  收藏  举报