题目
多组询问,每次把树上的一条简单路径中的点权扔入集合中,求该集合的子异和,子异和定义为所有非空子集的异或和的和,而且需要支持区间异或
分析
考虑某一位满足异或和为1的子集数,若设异或某一位为 k k k为1的数量为 h k h_k hk,那么结果应为 c n t k = 2 n − h k × ∑ i = 1 ⌊ h k 2 ⌋ C ( n , 2 i − 1 ) = 2 n − 1 cnt_k=2^{n-h_k}\times \sum_{i=1}^{\lfloor\frac{h_k}{2}\rfloor}C(n,2i-1)=2^{n-1} cntk=2n−hk×i=1∑⌊2hk⌋C(n,2i−1)=2n−1,竟然只与 h k hk hk是否为0有关,最终答案竟然变成了 2 n − 1 × o r s u m 2^{n-1}\times orsum 2n−1×orsum,但是如何实现区间异或,显然只有或是不够的,所以我们可能要引入与,分类讨论,其实也很好理解的呀
t a n d = ( t a n d & ! z ) ∣ ( ! t o r & z ) , t o r = ( ! t a n d & z ) ( t o r & ! z ) t_{and}=(t_{and}\& !z)|(!t_{or}\& z),t_{or}=(!t_{and}\&z)(t_{or}\& !z) tand=(tand&!z)∣(!tor&z),tor=(!tand&z)(tor&!z)
所以就树剖套线段树解决
代码
#include <cstdio>
#include <cctype>
#define rr register
#define getchar() (p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<13,stdin)),p1==p2?EOF:*p1++)
using namespace std;
typedef unsigned uit; const uit N=200101,mod=1000000007; struct node{uit y,next;}e[N<<1]; char buf[1<<13],*p1,*p2;
uit wnd[N<<2],wor[N<<2],p[N],lazy[N<<2],ls[N],n,tot,K=1,a[N],A[N],top[N],dep[N],fat[N],dfn[N],son[N],big[N];
inline uit iut(){
rr uit ans=0; rr char c=getchar();
while (!isdigit(c)) c=getchar();
while (isdigit(c)) ans=(ans<<3)+(ans<<1)+(c^48),c=getchar();
return ans;
}
inline void print(uit ans){
if (ans>9) print(ans/10);
putchar(ans%10+48);
}
inline uit mo(uit x,uit y){return x+y>=mod?x+y-mod:x+y;}
inline void change(uit k,uit z){
rr uit t1=wnd[k],t2=wor[k];
wnd[k]=(t1&~z)|(~t2&z),
wor[k]=(~t1&z)|(t2&~z);
lazy[k]^=z;
}
inline void pdown(uit k){
if (!lazy[k]) return;
change(k<<1,lazy[k]),
change(k<<1|1,lazy[k]);
lazy[k]=0;
}
inline void build(uit k,uit l,uit r){
if (l==r){wnd[k]=wor[k]=a[l]; return;}
rr uit mid=(l+r)>>1;
build(k<<1,l,mid);
build(k<<1|1,mid+1,r);
wnd[k]=wnd[k<<1]&wnd[k<<1|1],wor[k]=wor[k<<1]|wor[k<<1|1];
}
inline uit query(uit k,uit l,uit r,uit x,uit y){
if (l==x&&r==y) return wor[k];
pdown(k); rr uit mid=(l+r)>>1;
if (y<=mid) return query(k<<1,l,mid,x,y);
else if (x>mid) return query(k<<1|1,mid+1,r,x,y);
else return query(k<<1,l,mid,x,mid)|query(k<<1|1,mid+1,r,mid+1,y);
}
inline void update(uit k,uit l,uit r,uit x,uit y,uit z){
if (l==x&&r==y) {change(k,z); return;}
pdown(k); rr uit mid=(l+r)>>1;
if (y<=mid) update(k<<1,l,mid,x,y,z);
else if (x>mid) update(k<<1|1,mid+1,r,x,y,z);
else update(k<<1,l,mid,x,mid,z),update(k<<1|1,mid+1,r,mid+1,y,z);
wnd[k]=wnd[k<<1]&wnd[k<<1|1],wor[k]=wor[k<<1]|wor[k<<1|1];
}
inline void Update(uit x,uit y,uit z){
while (top[x]!=top[y]){
if (dep[top[x]]<dep[top[y]]) x^=y,y^=x,x^=y;
update(1,1,n,dfn[top[x]],dfn[x],z),x=fat[top[x]];
}
if (dep[x]>dep[y]) x^=y,y^=x,x^=y;
update(1,1,n,dfn[x],dfn[y],z);
}
inline uit Query(uit x,uit y){
rr uit ans=0,cnt=0;
while (top[x]!=top[y]){
if (dep[top[x]]<dep[top[y]]) x^=y,y^=x,x^=y;
ans|=query(1,1,n,dfn[top[x]],dfn[x]);
cnt+=dfn[x]-dfn[top[x]]+1,x=fat[top[x]];
}
if (dep[x]>dep[y]) x^=y,y^=x,x^=y;
cnt+=dfn[y]-dfn[x]+1,ans|=query(1,1,n,dfn[x],dfn[y]);
return 1ll*ans*p[cnt-1]%mod;
}
inline void dfs1(uit x,uit fa){
dep[x]=dep[fa]+1,fat[x]=fa,son[x]=1;
for (rr uit i=ls[x],mson=0;i;i=e[i].next)
if (e[i].y!=fa){
dfs1(e[i].y,x);
son[x]+=son[e[i].y];
if (son[e[i].y]>mson) big[x]=e[i].y,mson=son[e[i].y];
}
}
inline void dfs2(uit x,uit linp){
dfn[x]=++tot,a[tot]=A[x],top[x]=linp;
if (!big[x]) return; dfs2(big[x],linp);
for (rr uit i=ls[x];i;i=e[i].next)
if (e[i].y!=fat[x]&&e[i].y!=big[x]) dfs2(e[i].y,e[i].y);
}
signed main(){
n=iut(); rr int m=iut(); p[0]=1;
for (rr uit i=1;i<n;++i){
rr uit x=iut(),y=iut();
e[++K]=(node){y,ls[x]},ls[x]=K;
e[++K]=(node){x,ls[y]},ls[y]=K;
}
for (rr uit i=1;i<=n;++i) A[i]=iut(),p[i]=mo(p[i-1],p[i-1]);
dfs1(1,0),dfs2(1,1),build(1,1,n);
while (m--){
rr uit opt=iut(),x=iut(),y=iut(),w;
if ((opt&1)^1) w=iut();
if (opt&1) print(Query(x,y)),putchar(10);
else Update(x,y,w);
}
return 0;
}