[luogu 3690]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。

输入输出格式

输入格式:

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

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

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

输出格式:

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

输入输出样例

输入样例#1: 复制
3 3 
1
2
3
1 1 2
0 1 2 
0 1 1
输出样例#1: 复制
3
1

说明

数据范围: $1 \leq N, M \leq 3 \cdot {10}^5$

题解:

动态树练手。

  1 //Never forget why you start
  2 #include<iostream>
  3 #include<cstdio>
  4 #include<cstdlib>
  5 #include<cstring>
  6 #include<cmath>
  7 #include<algorithm>
  8 #define ll(x) lct[x].child[0]
  9 #define rr(x) lct[x].child[1]
 10 #define son(x,t) lct[x].child[t]
 11 using namespace std;
 12 int n,m;
 13 int read(){
 14   int ans=0,f=1;char i=getchar();
 15   while(i<'0'||i>'9'){if(i=='-')f=-1;i=getchar();}
 16   while(i>='0'&&i<='9'){ans=ans*10+i-'0';i=getchar();}
 17   return ans*f;
 18 }
 19 struct LCT{
 20   int child[2],fa,x,size,sum,rev;
 21   bool is_root;
 22 }lct[300005];
 23 void push_up(int root){
 24   if(!root)return;
 25   lct[root].sum=lct[root].x^lct[ll(root)].sum^lct[rr(root)].sum;
 26   lct[root].size=lct[ll(root)].size+lct[rr(root)].size+1;
 27 }
 28 int getson(int x){
 29   return x==son(lct[x].fa,1);
 30 }
 31 void push_rev(int x){
 32   if(!x)return;
 33   swap(ll(x),rr(x));
 34   lct[x].rev^=1;
 35 }
 36 void push_down(int x){
 37   if(lct[x].rev&&x){
 38     push_rev(ll(x));
 39     push_rev(rr(x));
 40     lct[x].rev^=1;
 41   }
 42 }
 43 void push(int x){
 44   if(!lct[x].is_root)push(lct[x].fa);
 45   push_down(x);
 46 }
 47 void rotate(int x){
 48   if(lct[x].is_root)return;
 49   int fa=lct[x].fa,fafa=lct[fa].fa,t=getson(x);
 50   son(fa,t)=son(x,!t);if(son(x,!t))lct[son(x,!t)].fa=fa;
 51   lct[fa].fa=x;son(x,!t)=fa;
 52   lct[x].fa=fafa;
 53   if(!lct[fa].is_root)son(fafa,son(fafa,1)==fa)=x;
 54   else lct[x].is_root=1,lct[fa].is_root=0;
 55   push_up(fa);
 56   push_up(x);
 57 }
 58 void splay(int x){
 59   push(x);
 60   for(int fa;!lct[x].is_root;rotate(x))
 61     if(!lct[fa=lct[x].fa].is_root)
 62       rotate(getson(fa)==getson(x)?fa:x);
 63 }
 64 void access(int x){
 65   int y=0;
 66   while(x){
 67     splay(x);
 68     lct[rr(x)].is_root=1;
 69     lct[rr(x)=y].is_root=0;
 70     push_up(x);
 71     x=lct[y=x].fa;
 72   }
 73 }
 74 void mroot(int x){
 75   access(x);
 76   splay(x);
 77   push_rev(x);
 78 }
 79 void link(int u,int v){
 80   mroot(u);
 81   lct[u].fa=v;
 82 }
 83 void cut(int u,int v){
 84   mroot(u);
 85   access(v);splay(v);
 86   lct[son(v,0)].fa=lct[v].fa;
 87   lct[son(v,0)].is_root=1;
 88   ll(v)=lct[v].fa=0;
 89   push_up(v);
 90 }
 91 int find(int x){
 92   access(x);
 93   splay(x);
 94   if(ll(x))x=ll(x);
 95   return x;
 96 }
 97 int main(){
 98   int i,j;
 99   n=read();m=read();
100   for(i=1;i<=n;i++){
101     lct[i].x=lct[i].sum=read();
102     lct[i].size=1;
103     ll(i)=rr(i)=lct[i].fa=0;
104     lct[i].is_root=1;
105   }
106   int a,b,c;
107   for(i=1;i<=m;i++){
108     c=read();a=read();b=read();
109     if(c==0){
110       mroot(a);
111       access(b);
112       splay(b);
113       printf("%d\n",lct[b].sum);
114     }
115     else if(c==1){
116       int p=find(a),q=find(b);
117       if(p!=q)link(a,b);
118     }
119     else if(c==2){
120       mroot(a);
121       access(b);
122       splay(b);
123       if(ll(b)==a)cut(a,b);
124     }
125     else{
126       mroot(a);
127       splay(a);
128       lct[a].x=b;
129       push_up(a);
130     }
131   }
132   return 0;
133 }

 

转载于:https://www.cnblogs.com/huangdalaofighting/p/8300952.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值