洛谷P3459 [POI2007]MEG-Megalopolis(樹鏈剖分,Splay)

洛谷題目傳送門 正解是樹狀數組維護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;
}
相關文章
相關標籤/搜索