LCT动态树-基础模板(luogu P3690)

本文深入探讨了动态树的实现与应用,特别聚焦于LinkCutTree数据结构,一种高效处理动态树操作的方法。文章详细解释了如何通过LinkCutTree进行路径查询、边的增删、节点权值更新等操作,提供了完整的代码示例,适用于解决复杂的图论问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

学习来自

P3690 【模板】Link Cut Tree (动态树)

给定n个点以及每个点的权值,要你处理接下来的m个操作。操作有4种。操作从0到3编号。点从1到n编号。

0:后接两个整数(x,y),代表询问从x到y的路径上的点的权值的xor和。保证x到y是联通的。

1:后接两个整数(x,y),代表连接x到y,若x到y已经联通则无需连接。

2:后接两个整数(x,y),代表删除边(x,y),不保证边(x,y)存在。

3:后接两个整数(x,y),代表将点x上的权值变成y。

#include<bits/stdc++.h>
#define il inline
#define pb push_back
#define ms(_data,v) memset(_data,v,sizeof(_data))
#define SZ(a) int((a).size())
#define ls ch[x][0]
#define rs ch[x][1]
using namespace std;
typedef long long ll;
const ll inf=0x3f3f3f3f;
const int N=3e5+5;
template <typename _Tp> il void read(_Tp&x) {
	char ch;bool flag=0;x=0;
	while(ch=getchar(),!isdigit(ch)) if(ch=='-')flag=1;
	while(isdigit(ch)) x=x*10+ch-'0',ch=getchar();
	if(flag) x=-x;
}
//il int Add(int &x,ll y) {return x=x+y>=mod?x+y-mod:x+y;}
//il int Mul(int &x,ll y) {return x=x*y>=mod?x*y%mod:x*y;}
int f[N],ch[N][2],v[N],s[N],st[N];
bool r[N];
il bool isroot(int x){//判断节点是否为一个Splay的根
	return ch[f[x]][0]==x || ch[f[x]][1]==x; 
} 
il void pushup(int x){//上传信息
	s[x]=s[ls]^s[rs]^v[x];
}
il void reverse(int x){//翻转
	swap(ls,rs),r[x]^=1;
}
il void pushdown(int x){//判断并释放懒标记
	if(r[x]){
		if(ls) reverse(ls);
		if(rs) reverse(rs);
		r[x]=0;
	}
}
il void rotate(int x){//一次旋转
	int y=f[x],z=f[y],k=(ch[y][1]==x),w=ch[x][!k];
	if(isroot(y))	ch[z][ch[z][1]==y]=x;
	ch[x][!k]=y,ch[y][k]=w;
	if(w) f[w]=y;
	f[y]=x,f[x]=z;
	pushup(y);
}
il void splay(int x){//所有操作的目标都是该Splay的根
	int y=x,z=0;
	st[++z]=y;
	while(isroot(y)) st[++z]=y=f[y];
	while(z) pushdown(st[z--]);
	while(isroot(x)){
		y=f[x],z=f[y];
		if(isroot(y)) rotate((ch[y][0]==x)^(ch[z][0]==y)?x:y);
		rotate(x);
	}
	pushup(x);
}

il void access(int x){//访问
	for(int y=0;x;x=f[y=x]){
		splay(x),rs=y,pushup(x);
	}
}
il void makeroot(int x){//将x换成根
	access(x),splay(x);
	reverse(x);
}
il int findroot(int x){//找根(在真实的树中的)
	access(x),splay(x);
	while(ls) pushdown(x),x=ls;
	splay(x);
	return x;
}
il void split(int x,int y){////提取路径 
	makeroot(x);
	access(y),splay(y);
}
il void link(int x,int y){//连边
	makeroot(x);
	if(findroot(y)!=x) f[x]=y;
}
il void cut(int x,int y){//断边
	makeroot(x);
	if(findroot(y)==x && f[y]==x && !ch[y][0]){
		f[y]=ch[x][1]=0;
		pushup(x);
	}
}
/*
//保证合法的情况下 
il void link(int x,int y){
	makeroot(x),f[x]=y;
}
il void cut(int x,int y){
	split(x,y);
	f[x]=ch[y][0]=0;
}
*/
int n,m,type,x,y;
int main() {
	read(n),read(m);
	for(int i=1; i<=n; ++i) read(v[i]);
	while(m--) {
		read(type),read(x),read(y);
		switch(type) {
			case 0:
				split(x,y);
				printf("%d\n",s[y]);
				break;
			case 1:
				link(x,y);
				break;
			case 2:
				cut(x,y);
				break;
			case 3:
				splay(x);
				v[x]=y;//先把x转上去再修改,不然会影响Splay信息的正确性
		}
	}
	return 0;
}








 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值