题意:给你一个数组,有两种操作,一种区间xor一个值,一个是查询区间xor的结果的种类数
做法一:
对于一个给定的区间,我们可以通过求解线性基的方式求出结果的种类数,而现在只不过将其放在线树上维护区间线性基。
用线段树去维护区间合并

#include <bits/stdc++.h> using namespace std; const int maxn = 1e5; struct node { int bas[30],lazy,st; void init() { memset(bas,0,sizeof(bas)); lazy = 0;st = 0; } int Count() { int ans = 0; for(int i = 0;i<=29;i++) { if(bas[i]) ans++; } return ans; } void add(int x) { for(int i = 29;i>=0;i--) { if((x>>i)&1){ if(bas[i])x^=bas[i]; else { bas[i] = x; break; } } } } node operator + (const node &a) const{ node ans; ans.init(); for(int i = 0;i<=29;i++) { ans.add(bas[i]); ans.add(a.bas[i]); } ans.add(st^a.st); ans.st = a.st; return ans; } }tr[8*maxn],ans; int n,q; void pushdown(int st) { if(tr[st].lazy) { tr[st<<1].lazy ^= tr[st].lazy; tr[st<<1].st ^= tr[st].lazy; tr[st<<1|1].lazy ^= tr[st].lazy; tr[st<<1|1].st ^= tr[st].lazy; tr[st].lazy = 0; } } void build(int l,int r,int st) { tr[st].init(); if(l == r) { scanf("%d",&tr[st].st); return ; } int mid = (l+r)>>1; build(l,mid,st<<1); build(mid+1,r,st<<1|1); tr[st] = tr[st<<1] + tr[st<<1|1]; } void update(int l,int r,int st,int L,int R,int d) { if(l>=L && r<=R) { tr[st].lazy ^= d; tr[st].st ^= d; return ; } pushdown(st); int mid = (l+r) >>1; if(L<=mid) update(l,mid,st<<1,L,R,d); if(R> mid) update(mid+1,r,st<<1|1,L,R,d); tr[st] = tr[st<<1] + tr[st<<1|1]; } void Query(int l,int r,int st,int L,int R) { if(l >= L && r <= R) { ans = ans + tr[st]; return ; } pushdown(st); int mid = (l+r) >>1; if(L<=mid) Query(l,mid,st<<1,L,R); if(R>mid) Query(mid+1,r,st<<1|1,L,R); tr[st] = tr[st<<1] + tr[st<<1|1]; } int main() { int op,l,r,d; scanf("%d %d",&n,&q); build(1,n,1); while(q--) { scanf("%d %d %d",&op,&l,&r); if(op == 1) { scanf("%d",&d); update(1,n,1,l,r,d); } else { ans.init(); Query(1,n,1,l,r); printf("%d ",1<<ans.Count()); } } return 0; }
做法二:
对原序列a进行差分,使得b[i] = a[i] ^ a[i+1],那么al,al+1,al+2,ar可以构成的一个异或和,在al,bl,bl+1,bl+2,br-1中肯定也可以被构造出来,因此二者是等价的。
对于a序列的区间[l,r]的更新实际上b序列上只有bl-1和br被影响,中间的数由于是两两所以抵消掉了。
所以现在就变成了单点更新线段树维护区间线性基,然后再用一个树状数组维护l位置被修改的值,这也用到了差分,这里的作用是要求a[l]的值。

#include <bits/stdc++.h> #define lson l,mid,rt<<1 #define rson mid+1,r,rt<<1|1 using namespace std; const int mx = 2e5 + 10; int n,m,a[mx],b[mx]; int pre[mx],mv; struct node{ int gao[31]; void add(int x){ for(int i=29;i>=0;i--){ if(x&(1<<i)){ if(!gao[i]){ gao[i] = x; break; }else x ^= gao[i]; } } } node operator + (node A)const { node ret = A; for(int i=29;i>=0;i--) if(gao[i]) ret.add(gao[i]); return ret; } }s[mx<<2]; void add(int x,int v){ while(x<=n){ pre[x] ^= v; x += x&(-x); } } int getpre(int x){ int ans = 0; while(x){ ans ^= pre[x]; x -= x&(-x); } return ans; } void build(int l,int r,int rt) { if(l==r){ b[l] = a[l]^a[l+1]; for(int i=29;i>=0;i--) if((1<<i)&b[l]){ s[rt].gao[i] = b[l]; break; } return ; } int mid = (l+r)>>1; build(lson);build(rson); s[rt] = s[rt<<1] + s[rt<<1|1]; } void update(int l,int r,int rt,int M) { if(l==r){ b[l] ^= mv; memset(s[rt].gao,0,sizeof(s[rt].gao)); for(int i=29;i>=0;i--) if((1<<i)&b[l]){ s[rt].gao[i] = b[l]; break; } return ; } int mid = (l+r)>>1; if(M<=mid) update(lson,M); else update(rson,M); s[rt] = s[rt<<1] + s[rt<<1|1]; } node query(int l,int r,int rt,int L,int R) { if(L<=l&&r<=R) return s[rt]; int mid = (l+r)>>1; if(L<=mid&&R>mid) return query(lson,L,R) + query(rson,L,R); if(L<=mid) return query(lson,L,R); return query(rson,L,R); } int main() { scanf("%d%d",&n,&m); for(int i=1;i<=n;i++) scanf("%d",a+i); if(n>1) build(1,n-1,1); int o,l,r; while(m--){ scanf("%d%d%d",&o,&l,&r); if(o==1){ scanf("%d",&mv); add(l,mv);add(r+1,mv); if(l>1) update(1,n-1,1,l-1); if(r<n) update(1,n-1,1,r); }else{ int v = a[l]^getpre(l); if(n==1||l==r) printf("%d ",v?2:1); else{ node ans = query(1,n-1,1,l,r-1); ans.add(v); int ret = 0; for(int i=29;i>=0;i--) if(ans.gao[i]) ret++; printf("%d ",1<<ret); } } } return 0; }