洛谷P3459 [POI2007]MEG-Megalopolis(树链剖分,Splay)

洛谷题目传送门
正解是树状数组维护dfn序上的前缀和,这样的思路真是又玄学又令我惊叹( 我太弱啦,根本想不到)Orz各路Dalao
今天考了这道题,数据范围还比洛谷的小,只有\(10^5\)(害我复制粘贴一波交上去RE),让我很放心地去想树剖了。
然而尴尬的是我不会树剖,却先学了LCT(再次暴露蒟蒻的本性
树剖的模型是,把土路视为权值,有修改,然后要查询某节点到根节点的权值和。没有换根的话,边权直接视为点权。
然后我干脆直接用Splay维护链剖分算啦(其实就是弱化板的LCT,有点像我弹飞绵羊的写法,但这里连link和cut都没有)
很明显,常数巨大。。。。。。不过我还是相信,能用树剖的一定不会卡掉Splay链剖分,所以我还是放心大胆地写了。
代码如下

#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;
}
posted @ 2018-02-24 14:57  Flash_Hu  阅读(262)  评论(4编辑  收藏  举报