题解 P5670 【秘籍-反复异或】
可能更好的体验
在我通过前,这题的正确代码都非常长而且思路比较复杂(也许)。这里说一种简单且易于理解的方法。
考虑到
异或运算是满足消去律的,所以如果一个数
我们考虑用bitset维护一个数在一段区间中的出现次数。那么合并相邻两个区间的信息,只需要将两个bitset异或起来即可。
用线段树维护这些bitset,单次查询的时间复杂度为
考虑对区间整体加上某个数对bitset的影响。那么,原来的第 b=(b<<x)|(b>>(1024-x))。
这里更新一个节点的信息是
最后要得到答案,我们有了一个长度为 bitset,可以
于是得到了一个时间复杂度
其中,后面的 bitset并每 bitset没法直接提取多位信息(我不太会的说)。不过由于时间复杂度瓶颈不在这里,所以使用 STL 的效率也是可以接受的。
这样做的话,可能会因为常数问题而过不去。注意到当区间比较小的时候,区间里的数很少,此时使用bitset进行运算是非常不划算的,因此在区间比较小的时候,进行暴力修改和查询。
这样就可以通过了,代码长度为
Code:
#include<iostream>
#include<bitset>
using namespace std;
typedef bitset<1024>BitSet;
const int N=1e5+6;
BitSet d[N];int tg[N],n,m,q,a[N];
void build(int l,int r,int o){
if(r-l+1<=64){
for(register int i=l;i<=r;++i)cin>>a[i],d[o].flip(a[i]);
}else{
const int mid=l+r>>1;
build(l,mid,o<<1),build(mid+1,r,o<<1|1);
d[o]=d[o<<1]^d[o<<1|1];
}
}
inline void pushdown(int o){
int&x=tg[o];
d[o<<1]=(d[o<<1]<<x)|(d[o<<1]>>(1024-x));
d[o<<1|1]=(d[o<<1|1]<<x)|(d[o<<1|1]>>(1024-x));
(tg[o<<1]+=x)&=1023,(tg[o<<1|1]+=x)&=1023;
x=0;
}
void modify(int l,int r,int o,const int&L,const int&R,const int&x){
if(r-l+1<=64){
const int lx=max(l,L),rx=min(r,R);
for(register int i=lx;i<=rx;++i)d[o].flip((a[i]+tg[o])&1023),d[o].flip((tg[o]+((a[i]+=x)&=1023))&1023);
}else
if(L<=l&&r<=R){
d[o]=(d[o]<<x)|(d[o]>>(1024-x));
(tg[o]+=x)&=1023;
}else{
if(tg[o])pushdown(o);
const int mid=l+r>>1;
if(L<=mid)modify(l,mid,o<<1,L,R,x);
if(mid<R)modify(mid+1,r,o<<1|1,L,R,x);
d[o]=d[o<<1]^d[o<<1|1];
}
}
void query(int l,int r,int o,const int&L,const int&R,BitSet&b){
if(r-l+1<=64){
const int lx=max(l,L),rx=min(r,R);
for(register int i=lx;i<=rx;++i)b.flip((a[i]+tg[o])&1023);
}else
if(L<=l&&r<=R)b^=d[o];else{
if(tg[o])pushdown(o);
const int mid=l+r>>1;
if(L<=mid)query(l,mid,o<<1,L,R,b);
if(mid<R)query(mid+1,r,o<<1|1,L,R,b);
}
}
int main(){
ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
cin>>n>>m>>q;
build(1,n,1);
while(q--){
int l,r,op,x;
cin>>op>>l>>r;
if(op==1){
cin>>x;
modify(1,n,1,l,r,x);
}else{
static BitSet b;
b.reset();
query(1,n,1,l,r,b);
int ans=0;
for(register int i=0;i<1024;++i)
ans^=b[i]*i;
ans&=(1<<m)-1;
cout<<ans<<'\n';
}
}
return 0;
}