题目链接:点我啊╭(╯^╰)╮
题目大意:
堆石块,每次可以从一堆中取至少一块,至多取完
先手,
次询问
①:询问
内有多少个子区间是
必胜
②:交换
与
解题思路:
根据
博弈,区间异或为
时
必败
那么预处理出异或前缀,用三维莫队即可
表示当前区间内出现前缀为
的数量,
为前缀
对于
的转移,直接用
讨论即可
对于
的转移,若用
,则不能讨论到整体区间
的情况
所以对于每个询问区间的
都要减一
时间戳修改可以在莫队中变换
与
的数值
也可以先全部变换完了之后从最后一个时间开始莫队
因为如果从
开始进行莫队的话一定要确保对
与
的修改
核心:用前缀异或性质 维护三维莫队
#include<bits/stdc++.h>
#define deb(x) cerr<<#x<<" = "<<(x)<<'\n';
using namespace std;
typedef long long ll;
const int maxn = 1e5 + 5;
int a[maxn], b[maxn], belong[maxn];
int cntq, cntc, n, m, size, bnum;
ll sum, cnt[1<<21], ans[maxn];
struct query {
int l, r, time, id;
} q[maxn];
struct modify {
int pos, pre, val;
} c[maxn];
int cmp(query a, query b) {
return (belong[a.l] ^ belong[b.l]) ? belong[a.l] < belong[b.l] :\
((belong[a.r] ^ belong[b.r]) ? belong[a.r] < belong[b.r] : a.time < b.time);
}
inline void add(int x){
sum += cnt[x];
cnt[x]++;
}
inline void del(int x){
--cnt[x];
sum -= cnt[x];
}
int main() {
while(~scanf("%d%d", &n, &m)){
size = pow(n, 2.0 / 3.0);
bnum = ceil((double)n / size);
for(int i=1; i<=bnum; ++i)
for(int j=(i-1)*size+1; j<=i*size; ++j)
belong[j] = i;
for(int i=1; i<=n; ++i){
scanf("%d", a+i);
b[i] = b[i-1] ^ a[i];
}
cntq = cntc = 0;
for(int i=1; i<=m; ++i) {
int op, pos;
scanf("%d", &op);
if(op == 1) {
++cntq;
scanf("%d%d", &q[cntq].l, &q[cntq].r);
--q[cntq].l;
q[cntq].time = cntc;
q[cntq].id = cntq;
} else {
++cntc;
scanf("%d", &pos);
c[cntc].pos = pos;
c[cntc].pre = b[pos];
c[cntc].val = b[pos+1] ^ a[pos];
b[pos] = b[pos+1] ^ a[pos];
swap(a[pos], a[pos+1]);
}
}
sort(q+1, q+cntq+1, cmp);
memset(cnt, 0, sizeof(cnt)), sum = 0;
int l = 1, r = 0, time = cntc, ql, qr, qt;
for(int i = 1; i <= cntq; ++i) {
ql = q[i].l, qr = q[i].r, qt = q[i].time;
while(l < ql) del(b[l++]);
while(l > ql) add(b[--l]);
while(r < qr) add(b[++r]);
while(r > qr) del(b[r--]);
while(time < qt) {
++time;
if(ql <= c[time].pos && c[time].pos <= qr) {
del(c[time].pre);
add(c[time].val);
}
b[c[time].pos] = c[time].val;
}
while(time > qt) {
if(ql <= c[time].pos && c[time].pos <= qr) {
del(c[time].val);
add(c[time].pre);
}
b[c[time].pos] = c[time].pre;
--time;
}
ans[q[i].id] = 1ll*(qr-ql+1)*(qr-ql)/2 - sum;
}
for(int i=1; i<=cntq; ++i) printf("%lld\n", ans[i]);
}
}