洛谷 P4219 [BJOI2014]大融合【LCT】

时间:2020-04-17
本文章向大家介绍洛谷 P4219 [BJOI2014]大融合【LCT】,主要包括洛谷 P4219 [BJOI2014]大融合【LCT】使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。

传送门
LCT 维护子树信息,对于每个节点,另开一个变量 \(f_2\) 记录其虚子树的总和,那么它的子树和就是 \(f[u]=f[ls]+f[rs]+val[u]+f_2[u]\)
这个维护操作就比较讲究了,在原树的形态发生变化的时候一定要注意即时修改 \(f_2\)
\(access\):将实边与虚边互换,那么 \(f_2[u]=f_2[u]-f[t]+f[rs]\)
\(link\):为一个点 \(y\) 增加虚子树 \(x\) ,所以 \(f_2[y]+=f[x]\)
其他操作均不需要单独的改值,因为并没有修改树的形态,\(cut\) 虽然改了树的形态但是也可以通过 pushup 自己更新到正确的值。

  • 注意对节点的值进行更改的时候一定要先将它转到 splay 的根,这样它现在的值才是正确的值,切记切记。
#include <bits/stdc++.h>
using namespace std;
const int N=1e5+10;

struct LinkCutTree{
	#define ls(x) (ch[x][0])
	#define rs(x) (ch[x][1])
	int fa[N],ch[N][2],siz[N],rev[N],siz2[N];
	int ident(int p,int f){return ch[f][1]==p;}
	void connect(int p,int f,int k){ch[f][k]=p;fa[p]=f;}
	bool ntroot(int p){return ls(fa[p])==p||rs(fa[p])==p;}
	void pushup(int p){siz[p]=siz[ls(p)]+siz[rs(p)]+1+siz2[p];}
	void Rev(int p){swap(ls(p),rs(p));rev[p]^=1;}
	void pushdw(int p){if(rev[p]) Rev(ls(p)),Rev(rs(p));rev[p]=0;}
	void rotate(int p){
		int f=fa[p],ff=fa[f],k=ident(p,f);
		connect(ch[p][k^1],f,k);
		fa[p]=ff;
		if(ntroot(f)) ch[ff][ident(f,ff)]=p;
		connect(f,p,k^1);
		pushup(f),pushup(p);
	}
	void pushall(int p){if(ntroot(p))pushall(fa[p]);pushdw(p);}
	void splay(int p){
		pushall(p);
		while(ntroot(p)){
			int f=fa[p],ff=fa[f];
			if(ntroot(f)) ident(p,f)^ident(f,ff)?rotate(p):rotate(f);
			rotate(p);
		}
	}
	void access(int p){for(int t=0;p;p=fa[t=p])splay(p),siz2[p]+=siz[rs(p)]-siz[t],rs(p)=t,pushup(p);}
	void makert(int p){access(p);splay(p);Rev(p);}
	int findrt(int p){access(p);splay(p);while(ls(p))p=ls(p),pushdw(p);splay(p);return p;}
	void split(int p,int q){makert(p);access(q);splay(q);}
	void link(int p,int q){makert(p);makert(q);fa[p]=q;siz2[q]+=siz[p];pushup(q);}
	void cut(int p,int q){split(p,q);if(ls(q)==p&&!rs(p)) fa[p]=ls(q)=0;pushup(p);pushup(q);}
	int getsize(int p){makert(p);return siz[p];}
}lct;

int n,q;

int main(){
	scanf("%d%d",&n,&q);
	while(q--){
		char opt[5];int x,y;
		scanf("%s%d%d",opt,&x,&y);
		if(opt[0]=='A') lct.link(x,y);
		else{
			lct.cut(x,y);
			int siz1=lct.getsize(x),siz2=lct.getsize(y);
			printf("%lld\n",1ll*siz1*siz2);
			lct.link(x,y);
		}
	}
	return 0;
}

原文地址:https://www.cnblogs.com/BakaCirno/p/12717550.html