I-Kuriyama Mirai and Exclusive Or
KeHe题解
diabolusexnihil题解
不过diabolusexnihil大佬的题解有一部分写错了应该是:每次分裂标记bl,ib_{l,i}bl,i需要给数组[l+2i−1,l+2i)⊕2i−1[l+2^{i-1},l+2^i)\oplus2^{i-1}[l+2i−1,l+2i)⊕2i−1然后标记分裂成bl,i−1,bl+2i−1,i−1b_{l,i-1},b_{l+2^{i-1},i-1}bl,i−1,bl+2i−1,i−1
#include<bits/stdc++.h>
using namespace std;
using ll=long long;
template <class T=int> T rd()
{T res=0;T fg=1;char ch=getchar();while(!isdigit(ch)) {if(ch=='-') fg=-1;ch=getchar();}while( isdigit(ch)) res=(res<<1)+(res<<3)+(ch^48),ch=getchar();return res*fg;
}
int n,q;
const int N=600010;
int a[N],tag[N];
bool b[N][22];
int main()
{n=rd(),q=rd();for(int i=1;i<=n;i++) a[i]=rd();while(q--){int op=rd(),l=rd(),r=rd(),x=rd();if(!op) // 操作一直接差分打标记{tag[l]^=x,tag[r+1]^=x;continue;}// 考虑区间[l,l+2^i) 每次考虑lowbit(x) ^(x+i) -> ^x^ifor(int i=0;i<=19;i++)if((x>>i&1)&&(l+(1<<i)-1)<=r)// 注意右端点{b[l][i]^=1;tag[l]^=(x>>i)<<i; tag[l+(1<<i)]^=(x>>i)<<i;//差分打标记l+=(1<<i);x+=(1<<i);}// 最后一段区间[l,r]// 此时如果l+2^i<r 那么 x>>i&1一定是0 同样 ^(x+i) -> ^x^i效仿上面做法即可for(int i=19;i>=0;i--)if((l+(1<<i)-1)<=r){b[l][i]^=1;tag[l]^=(x>>i)<<i;tag[l+(1<<i)]^=(x>>i)<<i;l+=(1<<i);x+=(1<<i);}}// 标记分裂for(int i=19;i>=1;i--)for(int j=1;j<=n;j++){if(!b[j][i]) continue;b[j][i-1]^=1;// 分裂标记1if(j+(1<<(i-1))<=n){b[j+(1<<(i-1))][i-1]^=1;// 分裂标记2// [l+2^{i-1},l+2^i) 需要打上抑或 2^{i-1}的标记tag[j+(1<<(i-1))]^=(1<<(i-1));if(j+(1<<i)<=n) tag[j+(1<<i)]^=(1<<(i-1));}}for(int i=1;i<=n;i++){tag[i]^=tag[i-1];printf("%d%c",a[i]^tag[i]," \n"[i==n]);}}
一辈子学不会的做法www