luogu P6018 [Ynoi2010]Fusion tree
阿新 • • 發佈:2020-07-14
之前膜你賽好像考過好幾次這種型別的題目,但我太菜了一直沒聽懂。
有個很常見的trick是統一維護一個點所有兒子的異或和,單獨維護父親。然後再上能維護全域性+1的01trie這題就做完了。
程式碼:
#include<cstdio> #include<cstring> #include<algorithm> #include<iostream> using namespace std; const int N=500009; int n,m,head[N],cnt,rt[N],p[N],F[N],addv[N]; struct Edge { int nxt,to; }g[N*2]; struct Trie { #define MaxN 25 int w[2*MaxN*N],ch[2*MaxN*N][2],xorv[2*MaxN*N],pool; void push_up(int k) { w[k]=xorv[k]=0; if(ch[k][0]) w[k]^=w[ch[k][0]], xorv[k]^=xorv[ch[k][0]]<<1; if(ch[k][1]) w[k]^=w[ch[k][1]], xorv[k]^=(xorv[ch[k][1]]<<1)|w[ch[k][1]]; } void Insert(int &k,int x,int dep) { if(!k) k=++pool; if(dep==MaxN) { w[k]^=1;return; } Insert(ch[k][x&1],x>>1,dep+1); push_up(k); } void addall(int k) { swap(ch[k][0],ch[k][1]); if(ch[k][0]) addall(ch[k][0]); push_up(k); } }T; void add(int from,int to) { g[++cnt].nxt=head[from]; g[cnt].to=to; head[from]=cnt; } int read() { int x=0; char c=getchar(); while(c<'0'||c>'9') c=getchar(); while(c>='0'&&c<='9') x=x*10+c-'0',c=getchar(); return x; } void init() { n=read(),m=read(); for (int x,y,i=1;i<n;i++) x=read(),y=read(), add(x,y),add(y,x); for (int i=1;i<=n;i++) p[i]=read(); } void dfs(int x,int fa) { for (int i=head[x];i;i=g[i].nxt) { int v=g[i].to; if(v==fa) continue; F[v]=x; dfs(v,x); T.Insert(rt[x],p[v],0); } } void work() { dfs(1,-1); int opt,x,v; while(m--) { opt=read(); if(opt==3) { x=read(); int ans=T.xorv[rt[x]]; if(x!=1) { int y=F[x]; if(y!=1) ans^=p[y]+addv[F[y]]; else ans^=p[y]; } printf("%d\n",ans); } else if(opt==2) { x=read(),v=read(); if(x!=1) T.Insert(rt[F[x]],p[x]+addv[F[x]],0), T.Insert(rt[F[x]],p[x]-v+addv[F[x]],0); p[x]-=v; } else { x=read(),T.addall(rt[x]),addv[x]++; if(x!=1) { int y=F[x]; if(y!=1) T.Insert(rt[F[y]],p[y]+addv[F[y]],0), T.Insert(rt[F[y]],p[y]+1+addv[F[y]],0); p[y]++; } } } } int main() { init(); work(); return 0; }