LCT进阶操作:子树查询

版权声明:本文为博主原创文章,未经博主允许必须转载。 https://blog.csdn.net/qq_35950004/article/details/88667172

具体的思想就是,我们的LCT看似只能用Splay维护链上的信息,但是我们可以再开一个数组把虚儿子的信息加到点上(如果可加的话),那么一条链的总信息就是这条链及其下面的虚儿子的总和,就是这条链的链顶的子树和。如果我们access了一个点,那么这个点的所有虚儿子的和+他自己就是他的子树和(因为下面没有重儿子)。
模板题
注意需要维护虚儿子信息的只有access和link,因为access会执行到最上面,所以上面的所有点也会被相应的更新,而link不会,所以link时需要保证两个点都是各自联通块的根。
AC Code:

#include<bits/stdc++.h>
#define maxn 100005
#define LL long long
using namespace std;

int n,q;
namespace LCT{
	int fa[maxn],siz[maxn],rev[maxn],ch[maxn][2],val[maxn];
	#define il inline 
	#define pa fa[x]
	il int inr(int x){ return ch[pa][1]==x; }
	il int isr(int x){ return ch[pa][0]!=x && ch[pa][1]!=x; }
	il void dt(int x){
		if(rev[x]){
			swap(ch[x][0],ch[x][1]),rev[x]=0;
			if(ch[x][0]) rev[ch[x][0]] ^= 1;
			if(ch[x][1]) rev[ch[x][1]] ^= 1;
		}
	}
	il void dtpath(int x){ if(!isr(x))dtpath(pa);dt(x);}
	il void upd(int x){ siz[x] = siz[ch[x][0]] + siz[ch[x][1]] + val[x]; }
	il void rot(int x){
		int y=fa[x],z=fa[y],c=inr(x);
		if(!isr(y)) ch[z][inr(y)]=x;
		(ch[y][c]=ch[x][!c])&&(fa[ch[y][c]]=y);
		fa[fa[ch[x][!c]=y]=x]=z;
		upd(y),upd(x);
	}
	il void splay(int x){
		for(dtpath(x);!isr(x);rot(x))
			if(!isr(pa)) rot(inr(pa)==inr(x)?pa:x);
	}
	il int access(int x,int y=0){
		for(;x;x=fa[y=x]){
			splay(x);
			if(ch[x][1]) val[x]+=siz[ch[x][1]];
			if(y) val[x]-=siz[y];
			ch[x][1] = y;
			upd(x);
		}
		return y;
	}
	il void bert(int x){
		access(x),splay(x),rev[x]^=1;
	}
	il void link(int x,int y){
		bert(x);bert(y);fa[x]=y;val[y]+=siz[x];
	}
	il LL query(int x,int y){
		bert(x),access(y),splay(y);
		return 1ll * val[x] * val[y];
	}
}

int main(){
	scanf("%d%d",&n,&q);
	for(int i=1;i<=n;i++) LCT::siz[i]=LCT::val[i]=1;
	char s[2];
	for(int u,v;q--;){
		scanf("%s",s);scanf("%d%d",&u,&v);
		if(s[0] == 'A') LCT::link(u,v);
		else printf("%lld\n",LCT::query(u,v));
	}
}

猜你喜欢

转载自blog.csdn.net/qq_35950004/article/details/88667172
LCT