动态树LCT模板

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

基本上就是模板题,没有什么好解释的

初始时是 n n n棵树,如果要动态连边的话 l i n k link link即可

#include <bits/stdc++.h>
#define inf 0x7fffffff
#define ll long long
//#define int long long
//#define double long double
#define re register int
#define void inline void
#define eps 1e-8
//#define mod 1e9+7
#define ls(p) p<<1
#define rs(p) p<<1|1
#define pi acos(-1.0)
#define pb push_back
#define P pair < int , int >
#define mk make_pair
using namespace std;
const int mod=1e9+7;
const int M=1e8+5;
const int N=1e5+5;//?????????? 4e8
struct node
{
	int fa,l,r,val,sum,add;
}e[N];
int n,m;
void reverse(int p)
{
	swap(e[p].l,e[p].r);
	e[p].add^=1;
}
void update(int p)
{
	e[p].sum=e[e[p].l].sum^e[e[p].r].sum^e[p].val;
}
bool ntroot(int p)
{
	return e[e[p].fa].l==p||e[e[p].fa].r==p;
}
bool ident(int p,int f)
{
	return e[f].r==p;
}
void connect(int p,int f,int s)
{
	if(s==0)  e[e[p].fa=f].l=p;
	else  e[e[p].fa=f].r=p;
}
void spread(int p)
{
	if(e[p].add)
	{
		if(e[p].l)  reverse(e[p].l);
		if(e[p].r)  reverse(e[p].r);
		e[p].add=0;
	}
}
void push(int p)
{
	if(ntroot(p))  push(e[p].fa);
	spread(p);
}
void rotate(int p)
{
	int f=e[p].fa;
	int ff=e[f].fa;
	int k=ident(p,f);
	if(k==0)  connect(e[p].r,f,k);
	else  connect(e[p].l,f,k);
	e[p].fa=ff;
	if(ntroot(f))
	{
		int op=ident(f,ff);
		if(op)  e[ff].r=p;
		else  e[ff].l=p; 
	}
	connect(f,p,k^1);
	update(f);update(p);
}
void splaying(int p)
{
	push(p);
	while(ntroot(p))
	{
		int f=e[p].fa;
		int ff=e[f].fa;
		if(ntroot(f))  ident(f,ff)^ident(p,f)?rotate(p):rotate(f);
		rotate(p);
	}
}
void access(int p)
{
//	cout<<p<<endl;
	for(re y=0;p;p=e[y=p].fa)
	{
		splaying(p);
		e[p].r=y;
		update(p);
	}
}
void mkroot(int p)
{
	access(p);
	splaying(p);
	reverse(p);
}
int findroot(int p)
{
	access(p);
	splaying(p);
	while(e[p].l)
	{
		push(p);
		p=e[p].l;
	}
	splaying(p);
	return p;
}
void link(int x,int y)
{
	mkroot(x);
	if(findroot(y)==x)  return;
	e[x].fa=y;
}
void cut(int x,int y)
{
	mkroot(x);
	if(findroot(y)!=x||e[y].fa!=x||e[y].l)  return;
	e[y].fa=e[x].r=0;
	update(x);
}
void split(int x,int y)
{
	mkroot(x);
	access(y);
	splaying(y);
}
void solve()
{
	cin>>n>>m;
	for(re i=1;i<=n;i++)  scanf("%d",&e[i].val);
	while(m--)
	{
		int op,x,y;
		scanf("%d %d %d",&op,&x,&y);
		if(op==0)
		{
			split(x,y);
			printf("%d\n",e[y].sum);
		}
		if(op==1)  link(x,y);
		if(op==2)  cut(x,y);
		if(op==3)
		{
			splaying(x);
			e[x].val=y;
			update(x);
		}
	}
}
signed main()
{
    int T=1;
//    cin>>T;
    for(int index=1;index<=T;index++)
    {
//    	printf("Case %d:\n",index);
        solve();
//        puts("");
    }
    return 0;
}
/*


1
6 5
0 0 0 122 499 8888




*/
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值