洛谷題目傳送門 正解是樹狀數組維護dfn序上的前綴和,這樣的思路真是又玄學又令我驚歎( ~~我太弱啦,根本想不到)~~Orz各路Dalao 今天考了這道題,數據範圍還比洛谷的小,只有$10^5$(害我複製粘貼一波交上去RE),讓我很放心地去想樹剖了。 然而尷尬的是我不會樹剖,卻先學了LCT(再次暴露蒟蒻的本性) 樹剖的模型是,把土路視爲權值,有修改,而後要查詢某節點到根節點的權值和。沒有換根的話,邊權直接視爲點權。 而後我乾脆直接用Splay維護鏈剖分算啦(其實就是弱化板的LCT,有點像我彈飛綿羊的寫法,但這裏連link和cut都沒有) 很明顯,常數巨大。。。。。。不過我仍是相信,能用樹剖的必定不會卡掉Splay鏈剖分,因此我仍是放心大膽地寫了。 代碼以下html
#include<cstdio> #define R register int #define I inline void #define lc c[x][0] #define rc c[x][1] #define G c=getchar() #define gc G;while(c<'-')G #define in(z) gc;z=c&15;G;\ while(c>'-')z*=10,z+=c&15,G const int N=250009; int f[N],c[N][2],s[N];//s表示路徑上土路總和 bool tu[N];//是否爲土路 inline bool nroot(R x){ return c[f[x]][0]==x||c[f[x]][1]==x; } I pushup(R x){ s[x]=s[lc]+s[rc]+tu[x]; } I rotate(R x){ R y=f[x],z=f[y],k=c[y][1]==x,w=c[x][!k]; if(nroot(y))c[z][c[z][1]==y]=x;c[x][!k]=y;c[y][k]=w; f[w]=y;f[y]=x;f[x]=z; pushup(y); } I splay(R x){ R y; while(nroot(x)){ if(nroot(y=f[x])) rotate((c[f[y]][0]==y)^(c[y][0]==x)?x:y); rotate(x); } pushup(x); } I access(R x){ for(R y=0;x;x=f[y=x]) splay(x),rc=y,pushup(x); }//Splay鏈剖分(彷佛全部函數節選自LCT) int main(){ R n,m,u,v,i,t; register char c; in(n); for(i=1;i<n;++i){ in(u);in(v); if(u>v)t=u,u=v,v=t;//題目保證了編號小的爲父親 f[v]=u;tu[v]=1; } in(m); for(i=n+m-1;i;--i){ gc; if(c=='A'){ in(u);in(v); if(u>v)t=u,u=v,v=t; splay(v);tu[v]=0;pushup(v);//轉到根再改 } else{ in(v); access(v);splay(v); printf("%d\n",s[v]); } } return 0; }