博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
[BZOJ3282]Tree(LCT)
阅读量:4983 次
发布时间:2019-06-12

本文共 2927 字,大约阅读时间需要 9 分钟。

 

3282: Tree

Time Limit: 30 Sec  Memory Limit: 512 MB
Submit: 2350  Solved: 1104
[][][]

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行,每行三个整数,分别代表操作类型和操作所需的量。
1<=N,M<=300000

 

 

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

Source

复习一下LCT板子。感觉异或有非常多的性质?至少异或和LCT关系比较密切。

Link-Cut Tree,一种可以支持在线维护森林以及连边,断边等森林操作的数据结构。主要难点在于区分“原树”与“Splay”树。

和Splay的区别不大,主要是Rot()和Splay()中的y!=rt改为了!isroot(y),以及Splay之前一定要记得将这棵Splay树pushdown。

注意要多upd(),修改的时候记得Splay()一下以保证期望复杂度。

for (int y=0; x; y=x,x=f[x]) splay(x),ch[x][1]=y,upd(x); 感觉是最难的一句话,要记牢。

代码应该会很难调,所以要提高熟练度和静态差错的能力。

有个奇怪的地方,在结构体内定义的函数好像可以不用分先后顺序。如下面的代码,split()用到了mkroot(),但前者可以放在后者的前面。

1 #include
2 #include
3 #define ls ch[x][0] 4 #define rs ch[x][1] 5 #define rep(i,l,r) for (int i=l; i<=r; i++) 6 using namespace std; 7 8 const int N=300100; 9 int n,Q,op,x,y;10 11 struct LCT{12 int v[N],sum[N],f[N],ch[N][2],rev[N];13 bool isroot(int x){ return (!f[x]) || (ch[f[x]][0]!=x && ch[f[x]][1]!=x); }14 void put(int x){ swap(ls,rs); rev[x]^=1; }15 void push(int x){ if (rev[x]) put(ls),put(rs),rev[x]=0; }16 void upd(int x){ sum[x]=sum[ls]^sum[rs]^v[x]; }17 void pd(int x){ if (!isroot(x)) pd(f[x]); push(x); }18 19 void rot(int x){20 int y=f[x],z=f[y],w=(ch[y][1]==x);21 if (!isroot(y)) ch[z][ch[z][1]==y]=x;22 f[x]=z; f[y]=x; f[ch[x][w^1]]=y;23 ch[y][w]=ch[x][w^1]; ch[x][w^1]=y; upd(y);24 }25 26 void splay(int x){27 pd(x);28 while (!isroot(x)){29 int y=f[x],z=f[y];30 if (!isroot(y)){ if ((ch[z][0]==y) ^ (ch[y][0]==x)) rot(x); else rot(y); }31 rot(x);32 }33 upd(x);34 }35 36 void access(int x){ for (int y=0; x; y=x,x=f[x]) splay(x),ch[x][1]=y,upd(x); }37 void split(int x,int y){ mkroot(x); access(y); splay(y); }38 void mkroot(int x){ access(x); splay(x); put(x); }39 void link(int x,int y){ mkroot(x); f[x]=y; }40 void cut(int x,int y){ split(x,y); ch[y][0]=f[x]=0; upd(y); }41 int find(int x){ access(x); splay(x); while (ls) x=ls; return x; }42 }T;43 44 int main(){45 freopen("bzoj3282.in","r",stdin);46 freopen("bzoj3282.out","w",stdout);47 scanf("%d%d",&n,&Q);48 rep(i,1,n) scanf("%d",&T.v[i]);49 while (Q--){50 scanf("%d%d%d",&op,&x,&y);51 if (op==0) T.split(x,y),printf("%d\n",T.sum[y]);52 if (op==1) if (T.find(x)!=T.find(y)) T.link(x,y);53 if (op==2) if (T.find(x)==T.find(y)) T.cut(x,y);54 if (op==3) T.v[x]=y,T.splay(x);55 }56 return 0;57 }

 

转载于:https://www.cnblogs.com/HocRiser/p/8544721.html

你可能感兴趣的文章
今日头条面试题汇总
查看>>
hdu 1305 Immediate Decodability
查看>>
基本数据类型
查看>>
laravel 配置sql日志
查看>>
基于注意力机制的群组推荐算法
查看>>
Android: 创建一个AlertDialog对话框,必须按确定或取消按钮才能关闭对话框,禁止按[返回键]或[搜索键]关闭...
查看>>
linux更改shell
查看>>
win7 64位系统 pl/sql 无法解析指定的连接标识符解决办法
查看>>
linux -- RPM 和 YUM
查看>>
给列表单元格加背景色
查看>>
knockoutjs 静动态数据、行为绑定,计算属性及Sync同步更新 Value值更新事件控制...
查看>>
关于.NET编程中各种事务的实现
查看>>
spring Boot加载bean
查看>>
学习笔记 UpdateXml() MYSQL显错注入
查看>>
51nod1455(dp)
查看>>
正则:校验名字,不严格校验手机号
查看>>
软件测试作业二 —— 对于Faults,Errors,Failures的认识的习题
查看>>
.net 给前台元素设置样式
查看>>
WPF学习:控件的模板
查看>>
小数据池 深浅拷贝 集合
查看>>