题目背景

动态树

题目描述

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

说明

数据范围: N,M<=3*10^5.

课上听老师讲的还蛮有道理的,然而调起来简直想打人hhh

不能完全按照splay的套路写。。例如以下的这个错误我调了一个点(...):
我写splay的时候rotate直接判断grandfather(x)如果是0的话就不用连x了,

但是当LCT这么写(我一开始改的是!isroot(fa),但是此时fa的father已经变了,所以gg)会挂。

得改成 if(ch[ffa][0]==fa||ch[ffa][1]==fa) then (balabla)

诸如此类的细节还有很多,,,反正多写写把。。。晚上再搞一道熟练熟练。

/*  若干splay维护树(森林)中的重链 

    每颗splay的中序遍历恰好是一条重链
从上走到下。 一个节点最多只能有一个偏爱儿子,
所以在access的时候要先把当前点旋到splay的根,
把右儿子(也就是在树中的偏爱儿子)断掉,
换成到access的点路径上的儿子。
*/
#include<bits/stdc++.h>
#define maxn 300005
using namespace std;
int n,m,val[maxn],opt,a,b;
struct LCT{
int len,ch[maxn][],f[maxn];
int tag[maxn],xr[maxn],q[maxn]; inline void init(){
memset(f,,sizeof(f));
memset(ch,,sizeof(ch));
memset(tag,,sizeof(tag));
} //更新节点信息
inline void update(int x){
xr[x]=xr[ch[x][]]^xr[ch[x][]]^val[x];
}
//标记下传
inline void pushdown(int x){
if(tag[x]){
tag[x]=,tag[ch[x][]]^=,tag[ch[x][]]^=;
swap(ch[x][],ch[x][]);
}
} inline int get(int x){
return ch[f[x]][]==x;
}
//判断一个节点是否为当前splay的根
inline bool isroot(int x){
return (ch[f[x]][]!=x&&ch[f[x]][]!=x);
}
//splay的旋转操作
inline void rotate(int x){
int fa=f[x],ffa=f[fa],tp=get(x);
ch[fa][tp]=ch[x][tp^],f[ch[fa][tp]]=fa;
ch[x][tp^]=fa,f[fa]=x;
f[x]=ffa;
if(ch[ffa][]==fa||ch[ffa][]==fa) ch[ffa][ch[ffa][]==fa]=x;
update(fa),update(x);
}
//旋到根
inline void splay(int x){
len=;
for(int i=x;;i=f[i]){
q[++len]=i;
if(isroot(i)) break;
}
for(;len;len--) pushdown(q[len]); while(!isroot(x)){
int y=f[x],z=f[y];
if(!isroot(y)) rotate((get(y)==get(x)?y:x));
rotate(x);
} }
//将一个点到它所在的树的根的路径上的边都变成重边
inline void access(int x){
for(int son=;x;son=x,x=f[x]) splay(x),ch[x][]=son,update(x);
}
//把一个节点搞成它所在树的根
inline void makeroot(int x){
access(x);
splay(x),tag[x]^=;
}
//找所在树的根
inline int find_root(int x){
access(x),splay(x);
while(ch[x][]) x=ch[x][];
return x;
}
//把y所在的树从y点接到x点上
inline void add(int x,int y){
makeroot(x),f[x]=y;
//不能更新,因为y不是x的重儿子
}
//把x和y点断开
inline void cut(int x,int y){
makeroot(x),access(y);
splay(y);
if(ch[y][]==x) ch[y][]=,f[x]=;
}
}M; int main(){
M.init();
scanf("%d%d",&n,&m);
for(int i=;i<=n;i++) scanf("%d",val+i),M.xr[i]=val[i];
while(m--){
scanf("%d%d%d",&opt,&a,&b);
if(!opt){
M.makeroot(a),M.access(b),M.splay(b);
printf("%d\n",M.xr[b]);
}
else if(opt==){
if(M.find_root(a)==M.find_root(b)) continue;
M.add(a,b);
}
else if(opt==){
if(M.find_root(a)!=M.find_root(b)) continue;
M.cut(a,b);
}
else{
M.access(a),M.splay(a);
val[a]=b,M.update(a);
}
} return ;
}

最新文章

  1. [Linux][Hadoop] 运行WordCount例子
  2. 【转】 TCP协议中的三次握手和四次挥手(图解)
  3. css transform skew变换
  4. js中的数组
  5. QTP之对测试用例的自动化过程的分解
  6. SQL 多条件查询
  7. Django初探--开发环境搭建(笔记)
  8. web标准(复习)--3 二列和三列布局
  9. Linux下网站根目录权限
  10. Bitmap上下合成图片
  11. RabbitMQ权限控制原理
  12. 【JVM】-NO.110.JVM.1 -【hsdis jitwatch 生成查看汇编代码】
  13. keepalive+nginx 热备跟负载均衡
  14. java-RAC Oracle 连接字符串
  15. 使用win10 hyper-v安装linux系统
  16. docker基本操作命令
  17. (1.5)DML增强功能-try catch及事务控制
  18. js 复制 功能
  19. linux杀进程
  20. 【NXP开发板应用—智能插排】4. PWM驱动

热门文章

  1. BZOJ3295: [Cqoi2011]动态逆序对 莫队
  2. node安装
  3. 在线输入RGB更改背景色
  4. SVN 服务器安装及配置(WIN7)
  5. CSS中z-index全解析
  6. 原型prototype与原型链__proto__
  7. Spring 学习笔记(三)之注解
  8. Spring - IoC(7): 延迟实例化
  9. sort函数_C++
  10. algorithm ch15 FastWay