實際上是僞ETT,上U裙問了下說真ETT還能換根,維護邊的歐拉序啥的,不過找不到論文就沒去學(node
這裏講的ETT是用平衡樹維護歐拉序,支持換父親,子樹加子樹查詢等操做。c++
題目要求1. 到根的路徑查詢 2. 子樹加 3. 換父親git
直接使用這種ETT便可。學習
值得注意的是,1就是帶歐拉序係數的前綴和(訪問過兩次的正負抵消,參見歐拉序性質)。spa
而後2就打tag,維護的東西有點多。code
3移動區間,就是提出來區間而後接到新的地方。get
具體維護方式是用樹上位置表示歐拉序,值存帶正負係數的權值,因此每次要從新找歐拉序是啥(歐拉序+1-1不變,但位置會變),就還要存一個father。其餘看代碼吧。qt
#include<bits/stdc++.h> using namespace std; #define ll long long int read(){ int x=0,pos=1;char ch=getchar(); for(;!isdigit(ch);ch=getchar()) if(ch=='-') pos=0; for(;isdigit(ch);ch=getchar()) x=(x<<1)+(x<<3)+ch-'0'; return pos?x:-x; } const int N = 3e5+200; #define FOR(i,a,b) for(int i=a;i<=b;i++) int ch[N][2],val[N],sz[N],tot,rt=0,lnk[N],end[N],fa[N],a[N],las[N]; ll sum[N],p[N],tp[N],tag[N],w[N]; struct node{ int v,nex; }edge[N*2]; int head[N],top=0; void add(int u,int v){ edge[++top].v=v; edge[top].nex=head[u]; head[u]=top; } void push_up(int now){ sz[now]=sz[ch[now][0]]+sz[ch[now][1]]+1; tp[now]=p[now]+tp[ch[now][0]]+tp[ch[now][1]]; sum[now]=w[now]+sum[ch[now][0]]+sum[ch[now][1]]; if(ch[now][0]) fa[ch[now][0]]=now; if(ch[now][1]) fa[ch[now][1]]=now; } void addtag(int now,ll nw){ w[now]+=p[now]*nw; sum[now]+=tp[now]*nw; tag[now]+=nw; } void push_down(int now){ if(tag[now]){ addtag(ch[now][0],tag[now]); addtag(ch[now][1],tag[now]); tag[now]=0; } } int new_node(int v,int typ){ sz[++tot]=1; w[tot]=sum[tot]=v*typ; val[tot]=rand(); p[tot]=tp[tot]=typ; return tot; } int merge(int x,int y){ push_down(x);push_down(y); if(!x||!y) return x+y; if(val[x]<val[y]){ ch[x][1]=merge(ch[x][1],y); push_up(x); return x; }else{ ch[y][0]=merge(x,ch[y][0]); push_up(y); return y; } } void spilt(int now,int k,int &x,int &y){ if(!now) x=y=0; else{ push_down(now); if(k<=sz[ch[now][0]]){ y=now,spilt(ch[now][0],k,x,ch[y][0]); }else{ x=now,spilt(ch[now][1],k-sz[ch[now][0]]-1,ch[x][1],y); } push_up(now); } } int rnk(int x){ int res=sz[ch[x][0]]+1; while(fa[x]){ if(ch[fa[x]][1]==x) res+=sz[ch[fa[x]][0]]+1; x=fa[x]; } return res; } int kth(int now,int k){ while(1){ if(k<=sz[ch[now][0]]){ now=ch[now][0]; }else if(k==sz[ch[now][0]]+1) return now; else{ k-=sz[ch[now][0]]+1,now=ch[now][1]; } } } char s[4]; void dfs(int now){ lnk[now]=new_node(a[now],1); rt=merge(rt,lnk[now]); for(int i=head[now];i;i=edge[i].nex){ int v=edge[i].v; dfs(v); } las[now]=new_node(a[now],-1); rt=merge(rt,las[now]); } ll query(int now){ int x,y; spilt(rt,rnk(lnk[now]),x,y); ll res=sum[x]; merge(x,y); return res; } void work(int now,int fx){ int x,y,z; spilt(rt,rnk(lnk[now])-1,x,z); fa[x]=fa[z]=0; spilt(z,rnk(las[now]),y,z); fa[y]=fa[z]=0; rt=merge(x,z); fa[rt]=0; spilt(rt,rnk(lnk[fx]),x,z); rt=merge(merge(x,y),z); fa[rt]=0; } void addt(int now,ll nw){ int x,y,z; spilt(rt,rnk(lnk[now])-1,x,z); fa[x]=fa[z]=0; spilt(z,rnk(las[now]),y,z); fa[y]=fa[z]=0; addtag(y,nw); rt=merge(merge(x,y),z); fa[rt]=0; } int main(){ srand(20040523); int n=read(); FOR(i,2,n){ int x=read(); add(x,i); } FOR(i,1,n) a[i]=read(); dfs(1); int T=read(); while(T--){ scanf("%s",s); if(s[0]=='Q'){ int x=read(); ll res=query(x); printf("%lld\n",res); }else if(s[0]=='C'){ int x=read(),fx=read(); work(x,fx); }else{ int x=read(),nw=read(); addt(x,nw); } } return 0; }
今天學了fhqtreap(準確說是前天,只是今天寫)和ETT 感受很久沒有像這樣學新東西寫板子,A板子題了,又找回了初三的感受。it
但願接下來一個月的訓練可以不忘初心。class