bzoj 3282 tree

3282: Tree

Time Limit: 30 Sec  Memory Limit: 512 MB
Submit: 1280  Solved: 559
[ Submit][ Status][ Discuss]

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。

 

Input

第1行两个整数,分别为N和M,代表点数和操作数。

第2行到第N+1行,每行一个整数,整数在[1,10^9]内,代表每个点的权值。

第N+2行到第N+M+1行,每行三个整数,分别代表操作类型和操作所需的量。

 

Output

对于每一个0号操作,你须输出X到Y的路径上点权的Xor和。

Sample Input

3 3
1
2
3
1 1 2
0 1 2
0 1 1

Sample Output

3
1

HINT

1<=N,M<=300000

Source




题解:lct模板题,需要注意的是在删边的时候,需要先判断连通性和是否存在关系,否则会出错


#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define N 300003
using namespace std;
int n,m;
int size[N],key[N],sum[N],ch[N][3],fa[N],rev[N],top,st[N];
int isroot(int x)
{
  return ch[fa[x]][0]!=x&&ch[fa[x]][1]!=x;
}
int get(int x)
{
  return ch[fa[x]][1]==x;
}
void update(int x)
{
 if (!x) return;
 size[x]=size[ch[x][0]]+size[ch[x][1]]+1;
 sum[x]=sum[ch[x][0]]^sum[ch[x][1]]^key[x];
}
void pushdown(int x)
{
  if(!x) return;
  if (rev[x])
  {
  	rev[ch[x][0]]^=1; rev[ch[x][1]]^=1; rev[x]=0;
  	swap(ch[x][0],ch[x][1]);
  }
}
void rotate(int x)
{
  int y=fa[x]; int z=fa[y]; int which=get(x);
  if (!isroot(y)) ch[z][ch[z][1]==y]=x;
  ch[y][which]=ch[x][which^1]; fa[ch[y][which]]=y;
  ch[x][which^1]=y; fa[y]=x; fa[x]=z;
  update(y); update(x);
}
void splay(int x)
{
 top=0; st[++top]=x;
 for (int i=x;!isroot(i);i=fa[i])
  st[++top]=fa[i];
 for (int i=top;i>=1;i--) pushdown(st[i]);
 while (!isroot(x))
  {
  	int y=fa[x];
  	if (!isroot(y)) rotate(get(x)==get(y)?y:x);
  	rotate(x);
  }
}
void access(int x)
{
 int t=0;
 while (x)
 {
 	splay(x); ch[x][1]=t; update(x);
 	t=x; x=fa[x];
 }
}
void rever(int x)
{
 access(x); splay(x); rev[x]^=1;
}
void cut(int x,int y)
{
  rever(x); access(y); splay(y); 
  if (ch[y][0]==x)
   ch[y][0]=fa[x]=0;
}
void link(int x,int y)
{
 rever(x); fa[x]=y; splay(x);
}
void change(int x,int y)
{
  key[x]=y; access(x); splay(x);
}
int find(int x)
{
 access(x); splay(x);
 while (ch[x][0]) x=ch[x][0];
 return x;
}
int main()
{
  scanf("%d%d",&n,&m);
  for (int i=1;i<=n;i++) scanf("%d",&key[i]),sum[i]=key[i];
  for (int i=1;i<=m;i++)
  {
  	int x,y,k; scanf("%d%d%d",&k,&x,&y);
  	if (k==1)
  	{
  	  if (find(x)==find(y)) continue;
  	  else link(x,y);
  	}
  	else
  	if (k==2)
  	{
  	  if(find(x)!=find(y)) continue;
	  cut(x,y);	
  	}
  	else
  	if (k==3)   change(x,y);
  	else
  	 {
  	   rever(x); access(y); splay(y); update(y);
  	   printf("%d\n",sum[y]);
  	 }
  }
}




  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值