【数据结构】LCT

为了方便自己阅读,将部分代码贴到 CSDN 上。

模板题

#include<bits/stdc++.h>
using namespace std;

inline void read(int &x) {
    int s=0;x=1;
    char ch=getchar();
    while(ch<'0'||ch>'9') {if(ch=='-')x=-1;ch=getchar();}
    while(ch>='0'&&ch<='9') s=(s<<3)+(s<<1)+ch-'0',ch=getchar();
    x*=s;
}

const int N=1e5+5;

int n, m;

struct Node{
	int s[2], p, v;
	int sum, rev;
}tr[N];
int stk[N];

void pushrev(int x){
	swap(tr[x].s[0], tr[x].s[1]);
	tr[x].rev^=1;
}

void pushup(int x){
	tr[x].sum=tr[tr[x].s[0]].sum^tr[x].v^tr[tr[x].s[1]].sum;
}

void pushdown(int x){
	if(tr[x].rev){
		pushrev(tr[x].s[0]), pushrev(tr[x].s[1]);
		tr[x].rev=0;
	}
}

bool isroot(int x){
	return tr[tr[x].p].s[0]!=x && tr[tr[x].p].s[1]!=x;
}

void rotate(int x){
	int y=tr[x].p, z=tr[y].p;
	int k=tr[y].s[1]==x;
	if(!isroot(y)) tr[z].s[tr[z].s[1]==y]=x;
	tr[x].p=z;
	tr[tr[x].s[k^1]].p=y, tr[y].s[k]=tr[x].s[k^1];
	tr[y].p=x, tr[x].s[k^1]=y;
	pushup(y), pushup(x);
}

void splay(int x){
	int top=0, r=x;
	stk[++top]=r;
	while(!isroot(r)) stk[++top]=r=tr[r].p;
	while(top) pushdown(stk[top--]);
	
	while(!isroot(x)){
		int y=tr[x].p, z=tr[y].p;
		if(!isroot(y))
			if((tr[y].s[1]==x) ^ (tr[z].s[1]==y)) rotate(x);
			else rotate(y);
		rotate(x);
	}
}

void access(int x){ // 建立从原树的根到 x 的路径,同时 x 成为(splay)根节点。
	int z=x;
	for(int y=0; x; y=x, x=tr[x].p){
		splay(x);
		tr[x].s[1]=y, pushup(x);
	}
	splay(z);
}

// !
void makeroot(int x){ // x 成为原树的根节点
	access(x);
	pushrev(x);
}

int findroot(int x){ // 找到 x 所在原树的根节点,再将原树根节点转到 splay 的根节点
	access(x);
	while(tr[x].s[0]) pushdown(x), x=tr[x].s[0];
	splay(x);
	return x;
}

void split(int x, int y){ // x, y 路径用 splay 维护起来,splay 根为 y
	makeroot(x);
	access(y);
}

void link(int x, int y){ // 若 x, y 不连通,连边
	makeroot(x);
	if(findroot(y)!=x) tr[x].p=y;
}

void cut(int x, int y){ // x, y 间若直接连边,删除之
	makeroot(x); // 让 y 一定是 x 的后继
	if(findroot(y)==x && tr[y].p==x && !tr[y].s[0]){
		tr[x].s[1]=tr[y].p=0;
		pushup(x);
	}
}

int main(){
	cin>>n>>m;
	for(int i=1; i<=n; i++) read(tr[i].v);
	
	while(m--){
		int op, x, y; read(op), read(x), read(y);
		if(op==0){
			split(x, y);
			cout<<tr[y].sum<<'\n';
		}
		else if(op==1) link(x, y);
		else if(op==2) cut(x, y);
		else if(op==3){
			splay(x);
			tr[x].v=y;
			pushup(x); // ?
		}
	}
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值