正题
题目链接:https://www.luogu.org/problemnew/show/P5127
题目大意
定义一个序列的子异和为所有自己的异或和的和。
然后有点权的树,要求支持路径异或和路径求子异和。
解题思路
首先树链剖分是肯定的,然后我们考虑用哪个数据结构。
从每个位单独分析,一个长度为nnn的集合,然后cntxcnt_xcntx表示有多少数的二进制第xxx位为000
然后对于一个位可以贡献的答案是2cntx−1∗2n−cntx=2n−12^{cnt_x-1}*2^{n-cnt_x}=2^{n-1}2cntx−1∗2n−cntx=2n−1,但是若cntx==0cnt_x==0cntx==0时答案是0。
也就是每个位如果cntx≠0cnt_x\neq 0cntx̸=0那么就可以贡献2x∗2n−12^x*2^{n-1}2x∗2n−1的答案。
其实我们发现区间或值为sum(or)sum(or)sum(or)那么答案就是2n−1∗sum(or)2^{n-1}*sum(or)2n−1∗sum(or)。
然后我们区间查询就可以用线段树搞了,我们考虑如何区间查询
我们依旧是每个位进行分析,若第xxx位为0那么保持不变,如果为1那么久等于∼sum(and)\sim sum(and)∼sum(and)
所以我们可以得出
sum(or)′=(sum(or)&∼a)∣(∼sum(and)&a)sum(or)'=(sum(or)\& \sim a)|(\sim sum(and)\&a)sum(or)′=(sum(or)&∼a)∣(∼sum(and)&a)
然后我们多维护一个sum(and)sum(and)sum(and)
sum(and)′=(sum(and)&∼a)∣(∼sum(or)&a)sum(and)'=(sum(and)\& \sim a)|(\sim sum(or)\&a)sum(and)′=(sum(and)&∼a)∣(∼sum(or)&a)
圆满解决该题
codecodecode
#include<cstdio>
#include<algorithm>
#define ll long long
using namespace std;
const ll N=201000,XJQ=1e9+7;
struct Tree_node{ll l,r,sor,sand,lazy;
};
struct Edge_node{ll to,next;
}a[N*2];
ll tot,ls[N],n,m,w[N],cnt,pow[N];
ll id[N],siz[N],seg[N],son[N],top[N],dep[N],f[N];
struct Line_Cut_Tree{Tree_node t[N*4];ll ans,Dig;void build(ll x,ll l,ll r){t[x].l=l;t[x].r=r;if(l==r){t[x].sor=t[x].sand=w[id[l]];return;}ll mid=(l+r)/2;build(x*2,l,mid);build(x*2+1,mid+1,r);t[x].sor=t[x*2].sor|t[x*2+1].sor;t[x].sand=t[x*2].sand&t[x*2+1].sand;}void updata(ll x,ll w){ll sor=t[x].sor,sand=t[x].sand;t[x].sor=(sor&(~w))|((~sand)&w);t[x].sand=(sand&(~w))|((~sor)&w);t[x].lazy^=w;}void downdata(ll x){if(!t[x].lazy) return;updata(x*2,t[x].lazy);updata(x*2+1,t[x].lazy);t[x].lazy=0;}ll ask(ll x,ll l,ll r){if(t[x].l==l&&t[x].r==r)return t[x].sor;downdata(x);if(r<=t[x*2].r) return ask(x*2,l,r);if(l>=t[x*2+1].l) return ask(x*2+1,l,r);return ask(x*2,l,t[x*2].r)|ask(x*2+1,t[x*2+1].l,r);t[x].sor=t[x*2].sor|t[x*2+1].sor;t[x].sand=t[x*2].sand&t[x*2+1].sand;}void change(ll x,ll l,ll r,ll val){if(t[x].l==l&&t[x].r==r){updata(x,val);return;}downdata(x);if(r<=t[x*2].r) change(x*2,l,r,val);else if(l>=t[x*2+1].l) change(x*2+1,l,r,val);else change(x*2,l,t[x*2].r,val),change(x*2+1,t[x*2+1].l,r,val);t[x].sor=t[x*2].sor|t[x*2+1].sor;t[x].sand=t[x*2].sand&t[x*2+1].sand;}
}Tree;
void addl(ll x,ll y)
{a[++tot].to=y;a[tot].next=ls[x];ls[x]=tot;
}
void dfs(ll x,ll fa){siz[x]=1;f[x]=fa;dep[x]=dep[fa]+1;for(ll i=ls[x];i;i=a[i].next){ll y=a[i].to;if(y==fa) continue;dfs(y,x);siz[x]+=siz[y];if(siz[son[x]]<siz[y])son[x]=y;}
}
void dfs2(ll x,ll fa){seg[x]=++cnt;id[cnt]=x;if(son[x]){top[son[x]]=top[x];dfs2(son[x],x);}for(ll i=ls[x];i;i=a[i].next){ll y=a[i].to;if(y==fa||y==son[x]) continue;top[y]=y;dfs2(y,x);}
}
void push_change(ll x,ll y,ll z){while(top[x]!=top[y]){if(dep[top[x]]<dep[top[y]])swap(x,y);Tree.change(1,seg[top[x]],seg[x],z);x=f[top[x]];}if(dep[x]>dep[y]) swap(x,y);Tree.change(1,seg[x],seg[y],z);return;
}
ll push_ask(ll x,ll y){ll cnt=0,ans=0;while(top[x]!=top[y]){if(dep[top[x]]<dep[top[y]])swap(x,y);ans|=Tree.ask(1,seg[top[x]],seg[x]);cnt+=seg[x]-seg[top[x]]+1;x=f[top[x]];}if(dep[x]>dep[y]) swap(x,y);ans|=Tree.ask(1,seg[x],seg[y]);cnt+=seg[y]-seg[x]+1;return ans*pow[cnt-1]%XJQ;
}
int main()
{scanf("%lld%lld",&n,&m);for(ll i=1;i<n;i++){ll x,y;scanf("%lld%lld",&x,&y);addl(x,y);addl(y,x);}pow[0]=1;for(ll i=1;i<=n;i++)pow[i]=(pow[i-1]*2)%XJQ;for(ll i=1;i<=n;i++)scanf("%lld",&w[i]);dfs(1,0);top[1]=1;dfs2(1,0);Tree.build(1,1,n);for(ll i=1;i<=m;i++){ll ts,a,b,c;scanf("%lld%lld%lld",&ts,&a,&b);if(ts==1)printf("%lld\n",push_ask(a,b));elsescanf("%lld",&c),push_change(a,b,c);}
}