bzoj3282 Tree LCT

本文介绍了一道涉及LCT树的数据结构算法题,通过四种操作处理点权值的XOR和,包括路径查询、边的添加与删除及点权值更新。提供了完整的C++实现代码。

Description


给定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。

Solution


LCT板子题,写这个就是为了练手。。。没啥好说的
一个比较坑的地方就是题目“不保证(x,y)存在”,也就是说可能存在x、y连通但是x、y不相邻这样的cut(x,y),这个判一下就好了

Code


#include <stdio.h>
#include <string.h>
#include <algorithm>
#define rep(i,st,ed) for (int i=st;i<=ed;++i)

const int N=300005;

struct treeNode {
	int son[2],fa,sum,val;
	bool is_root,rev;
} t[N];

int read() {
	int x=0,v=1; char ch=getchar();
	for (;ch<'0'||ch>'9';v=(ch=='-')?(-1):(v),ch=getchar());
	for (;ch<='9'&&ch>='0';x=x*10+ch-'0',ch=getchar());
	return x*v;
}

void push_up(int x) {
	t[x].sum=t[x].val;
	if (t[x].son[0]) t[x].sum^=t[t[x].son[0]].sum;
	if (t[x].son[1]) t[x].sum^=t[t[x].son[1]].sum;
}

void push_down(int x) {
	if (!x||!t[x].rev) return ;
	std:: swap(t[x].son[0],t[x].son[1]);
	if (t[x].son[0]) t[t[x].son[0]].rev^=1;
	if (t[x].son[1]) t[t[x].son[1]].rev^=1;
	t[x].rev=0;
}

void remove(int x) {
	if (!t[x].is_root) remove(t[x].fa);
	push_down(x);
}

void rotate(int x) {
	if (t[x].is_root) return ;
	int y=t[x].fa,z=t[y].fa;
	int k=t[y].son[1]==x;
	t[y].son[k]=t[x].son[!k];
	if (t[x].son[!k]) t[t[x].son[!k]].fa=y;
	t[y].fa=x; t[x].son[!k]=y;
	t[x].fa=z;
	if (t[y].is_root) {
		t[x].is_root=1;
		t[y].is_root=0;
	} else t[z].son[t[z].son[1]==y]=x;
	push_up(y); push_up(x);
}

void splay(int x) {
	remove(x);
	for (;!t[x].is_root;) {
		int y=t[x].fa,z=t[y].fa;
		if (!t[y].is_root) {
			if ((t[z].son[1]==y)^(t[y].son[1]==x)) rotate(x);
			else rotate(y);
		}
		rotate(x);
	}
}

void access(int x) {
	int y=0;
	while (x) {
		splay(x);
		t[t[x].son[1]].is_root=1;
		t[t[x].son[1]=y].is_root=0;
		push_up(x);
		y=x; x=t[x].fa;
	}
}

void mroot(int x) {
	access(x); splay(x); t[x].rev^=1;
}

void link(int x,int y) {
	mroot(x); t[x].fa=y;
}

void cut(int x,int y) {
	mroot(x); access(y); splay(y);
	if (t[y].son[0]==x&&t[x].son[1]==0) {
		t[y].son[0]=t[x].fa=0;
		t[x].is_root=1; push_up(y);
	}
}

int find(int x) {
	access(x); splay(x);
	for (;t[x].son[0];) x=t[x].son[0];
	return x;
}

int main(void) {
	freopen("data.in","r",stdin);
	freopen("myp.out","w",stdout);
	int n=read(),m=read();
	rep(i,1,n) t[i].val=t[i].sum=read(),t[i].is_root=1;
	for (int opt,x,y;m--;) {
		opt=read(),x=read(),y=read();
		if (opt==0) {
			mroot(x); access(y); splay(y);
			printf("%d\n", t[y].sum);
		} else if (opt==1) {
			if (find(x)!=find(y)) link(x,y);
		} else if (opt==2) {
			if (find(x)==find(y)) cut(x,y);
		} else {
			access(x); splay(x); t[x].val=y; push_up(x);
		}
	}
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值