洛谷题目传送门 正解是树状数组维护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; }