模板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≤N,M≤3⋅105

算法原理提供可靠网址:

zyys

这道题用到的技巧:

 

找根:$makeroot(o)$后一直往左走。最后一个节点就是根。(理由:由于$LCT$中$splay$的性质:按深度作为键值);

 

判断是否之间有边:再$cut$之前,判断根的左儿子是否是另外一个点。(理由:若存在边,则包含这条边的$splay$只有两个节点)。

  1 #include<iostream>
  2 #include<cstdio>
  3 #include<cstring>
  4 #include<algorithm>
  5 #include<cmath>
  6 #include<queue>
  7 using namespace std;
  8 int xr[300005],ch[300005][2],val[300005],pre[300005],n,m;
  9 bool isrt[300005],rev[300005];
 10 void pushup(int o)
 11 {
 12   if (!o) return;
 13   xr[o]=xr[ch[o][0]]^xr[ch[o][1]]^val[o];
 14 }
 15 void pushdown(int o)
 16 {
 17   if (!o) return;
 18   if (rev[o])
 19     {
 20       int ls=ch[o][0],rs=ch[o][1];
 21       if (ls)
 22     {
 23       rev[ls]^=1;
 24       swap(ch[ls][0],ch[ls][1]);
 25     }
 26       if (rs)
 27     {
 28       rev[rs]^=1;
 29       swap(ch[rs][0],ch[rs][1]);
 30     }
 31       rev[o]=0;
 32     }
 33 }
 34 void push(int o)
 35 {
 36   if (isrt[o]==0)
 37       push(pre[o]);
 38   pushdown(o);
 39 }
 40 void rotate(int o,bool kind)
 41 {
 42   int p=pre[o];
 43   ch[p][!kind]=ch[o][kind];pre[ch[o][kind]]=p;
 44   if (isrt[p]) isrt[o]=1,isrt[p]=0;
 45   else ch[pre[p]][ch[pre[p]][1]==p]=o;
 46   pre[o]=pre[p];
 47   ch[o][kind]=p;pre[p]=o;
 48   pushup(p);pushup(o);
 49 }
 50 void splay(int o)
 51 {
 52   push(o);
 53   while (isrt[o]==0)
 54     {
 55       if (isrt[pre[o]])
 56     rotate(o,ch[pre[o]][0]==o);
 57       else
 58     {
 59       int p=pre[o],kind=ch[pre[p]][0]==p;
 60       if (ch[p][kind]==o)
 61         rotate(o,!kind),rotate(o,kind);
 62       else rotate(p,kind),rotate(o,kind);
 63     }
 64     }
 65 }
 66 void access(int o)
 67 {
 68   int y=0;
 69   while (o)
 70     {
 71       splay(o);
 72       //xr[o]^=xr[ch[o][1]];
 73       isrt[ch[o][1]]=1;isrt[ch[o][1]=y]=0;
 74       pushup(o);
 75       o=pre[y=o];
 76     }
 77 }
 78 void makeroot(int o)
 79 {
 80   access(o);
 81   splay(o);
 82   rev[o]^=1;
 83   swap(ch[o][0],ch[o][1]);
 84 }
 85 int find(int o)
 86 {
 87   makeroot(o);
 88   access(o);splay(o);
 89   while (ch[o][0])
 90     {
 91       o=ch[o][0];
 92     }
 93   return o;
 94 }
 95 void link(int x,int y)
 96 {
 97   makeroot(x);
 98   pre[x]=y;
 99 }
100 void cut(int x,int y)
101 {
102   makeroot(x);access(y);splay(y);
103   if (ch[y][0]!=x) return;
104   pre[x]=0;
105   ch[y][0]=0;
106   isrt[x]=1;
107   pushup(y);
108 }
109 int main()
110 {int i,c,x,y;
111   cin>>n>>m;
112   for (i=1;i<=n;i++)
113     {
114       scanf("%d",&val[i]);
115       xr[i]=val[i];isrt[i]=1;
116     }
117   for (i=1;i<=m;i++)
118     {
119       scanf("%d%d%d",&c,&x,&y);
120       if (c==0)
121     {
122       makeroot(y);
123       access(x);
124       splay(x);
125       printf("%d\n",xr[x]);
126     }
127       else if (c==1)
128     {
129       int p=find(x),q=find(y);
130       if (p!=q) link(x,y);
131     }
132       else if (c==2)
133     {
134       cut(x,y);
135     }
136       else if (c==3)
137     {
138       val[x]=y;
139       makeroot(x);
140       pushup(x);
141     }
142     }
143 }

 

posted @ 2018-01-16 14:10  Z-Y-Y-S  阅读(221)  评论(0编辑  收藏  举报