luoguP6018 [Ynoi2010]Fusion tree 01trie
今年省选考了这个技巧,感觉之前没做过类似的题的话现场挺难想出来的.
我们发现对 1 个数 +1 可以看作从低到高位的第一个 0 修改成 1,该 0 后面的 1 修改成 0.
将一个节点的所有儿子对应的数放到该节点对应的 01 trie 中进行修改的话就是将 0,1 翻转.
翻转后走 0 那边,然后递归地进行翻转就行.
然后注意在插入地时候即使 v=0 也要一直递归下去,因为我们是从低位向高位进行插入.
code:
#include <cstdio> #include <algorithm> #include <cstring> #define MA 20 #define N 1000009 #define ll long long #define lson s[x].ch[0] #define rson s[x].ch[1] #define setIO(s) freopen(s".in","r",stdin) using namespace std; int n,m,edges,tot; int hd[N],to[N<<1],nex[N<<1],fa[N],rt[N],a[N],addv[N]; struct data { int si,sum,cur,ch[2]; }s[N*30]; void pushup(int x) { s[x].sum=s[lson].sum^s[rson].sum; if(s[rson].si&1) s[x].sum+=1<<s[rson].cur; } void ins(int x,int v,int cur) { if(cur>20) return; if(v&1) { if(!rson) { rson=++tot; s[rson].cur=cur; } ++s[rson].si; ins(rson,v>>1,cur+1); } else { if(!lson) { lson=++tot; s[lson].cur=cur; } ++s[lson].si; ins(lson,v>>1,cur+1); } pushup(x); } void del(int x,int v,int cur=0) { if(cur>20) return; if(v&1) { --s[rson].si; del(rson,v>>1,cur+1); } else { --s[lson].si; del(lson,v>>1,cur+1); } pushup(x); } void upd(int x) { if(!x) return; swap(lson,rson),upd(lson),pushup(x); } void add(int u,int v) { nex[++edges]=hd[u],hd[u]=edges,to[edges]=v; } void dfs(int x,int ff) { fa[x]=ff; for(int i=hd[x];i;i=nex[i]) if(to[i]!=ff) dfs(to[i],x); } char *p1,*p2,buf[100000]; #define nc() (p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++) int rd() { char c; int x=0; do { c=nc(); } while(c<48); while(c>47) { x=(((x<<2)+x)<<1)+(c^48),c=nc(); } return x; } int main() { // setIO("input"); // freopen("input.out","w",stdout); int x,y,z; n=rd(),m=rd(); for(int i=1;i<n;++i) { x=rd(),y=rd(); add(x,y),add(y,x); } for(int i=1;i<=n;++i) a[i]=rd(); dfs(1,0); for(int i=1;i<=n;++i) { rt[i]=++tot; for(int j=hd[i];j;j=nex[j]) { y=to[j]; if(y==fa[i]) continue; ins(rt[i],a[y],0); } } int op; for(int i=1;i<=m;++i) { op=rd(); if(op==1) { x=rd(); upd(rt[x]); if(fa[x]) { z=fa[fa[x]]; if(z) { del(rt[z],a[fa[x]]+addv[z]); ins(rt[z],a[fa[x]]+addv[z]+1,0); } ++a[fa[x]]; } ++addv[x]; } if(op==2) { x=rd(),y=rd(); if(fa[x]) { del(rt[fa[x]],a[x]+addv[fa[x]]); ins(rt[fa[x]],a[x]+addv[fa[x]]-y,0); } a[x]-=y; } if(op==3) { x=rd(); printf("%d\n",s[rt[x]].sum^(a[fa[x]]+addv[fa[fa[x]]])); } } return 0; }