https://codeforces.com/contest/242/problem/E
区间异或与区间求和
思路:我们只需要建20颗线段树,存每一位的值。每次更新成段更新对应位,查询时求出整个区间每一位上的值 还原成贡献就行。
#include<bits/stdc++.h> #define lson l,m,rt<<1 #define rson m+1,r,rt<<1|1 using namespace std; typedef long long ll; const int maxn = 100000+5; int lazy[maxn<<2],tree[25][maxn<<2],a[maxn]; void push_up(int rt){ for(int i=0;i<20;i++) tree[i][rt]=tree[i][rt<<1]+tree[i][rt<<1|1]; } void push_down(int l,int r,int rt){ if(lazy[rt]){ int m=(l+r)>>1; lazy[rt<<1]^=lazy[rt]; lazy[rt<<1|1]^=lazy[rt]; for(int i=0;i<20;i++){ if(!(lazy[rt]&(1<<i))) continue; tree[i][rt<<1]=m-l+1-tree[i][rt<<1]; tree[i][rt<<1|1]=r-m-tree[i][rt<<1|1]; } lazy[rt]=0; } } void build(int l,int r,int rt){ if(l==r){ for(int i=0;i<20;i++){ if(!(a[l]&(1<<i))) continue; tree[i][rt]=1; } return ; } int m=(l+r)>>1; build(lson); build(rson); push_up(rt); } void update(int l,int r,int rt,int L,int R,int val){ if(L<=l&&r<=R){ lazy[rt]^=val; for(int i=0;i<20;i++){ if(!(val&(1<<i))) continue; tree[i][rt]=r-l+1-tree[i][rt]; //整个区间异或 相同为0所以减去tree[i][rt] } return ; } push_down(l,r,rt); int m=(l+r)>>1; if(L<=m) update(lson,L,R,val); if(R>m) update(rson,L,R,val); push_up(rt); } ll query(int l,int r,int rt,int L,int R){ if(L<=l&&r<=R){ ll ans=0; for(int i=0;i<20;i++){ ans+=(ll)tree[i][rt]<<i; } return ans; } int m=(l+r)>>1; push_down(l,r,rt); ll res=0; if(L<=m) res+=query(lson,L,R); if(R>m) res+=query(rson,L,R); return res; } int main(){ int n,m; scanf("%d",&n); for(int i=1;i<=n;i++){ scanf("%d",&a[i]); } build(1,n,1); scanf("%d",&m); for(int i=1;i<=m;i++){ int op,l,r,val; scanf("%d",&op); if(op==1){ scanf("%d %d",&l,&r); cout<<query(1,n,1,l,r)<<" "; }else { scanf("%d %d %d",&l,&r,&val); update(1,n,1,l,r,val); } } return 0; }