题目背景

动态树

题目描述

给定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}^51≤N,M≤3⋅105

看了一下午的讲解

看了一晚上的代码

算是差不多理解了,不过还有一个潜在的隐患没有解决,就是代码里那个玄学的pushdown函数

等搞懂了再整理吧

// luogu-judger-enable-o2
// luogu-judger-enable-o2
// luogu-judger-enable-o2
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int MAXN= * 1e5 + ;
inline int read()
{
char c = getchar();int x = ,f = ;
while(c < '' || c > ''){if(c == '-')f = -;c = getchar();}
while(c >= '' && c <= ''){x = x * + c - '',c = getchar();}
return x * f;
}
#define fa(x) T[x].f
#define ls(x) T[x].ch[0]
#define rs(x) T[x].ch[1]
int v[MAXN];
struct node {
int f, ch[], s;
bool r;
}T[MAXN];
int ident(int x) {
return T[fa(x)].ch[] == x ? : ;//判断该节点是父亲的哪个儿子
}
int connect(int x,int fa,int how) {
T[x].f=fa;
T[fa].ch[how]=x;//连接
}
inline bool IsRoot(int x) {//若为splay中的根则返回1 否则返回0
return ls( fa(x) ) != x && rs( fa(x) ) != x;
//用到了两个性质
//1.若x与fa(x)之间的边是虚边,那么它的父亲的孩子中不会有他(不在同一个splay内)
//2. splay的根节点与其父亲之间的边是虚边
}
void update(int x) {
T[x].s = T[ls(x)].s ^ T[rs(x)].s ^ v[x];//维护路径上的异或和
}
void pushdown(int x) {
if(T[x].r) {
swap(ls(x),rs(x));
T[ls(x)].r ^= ;
T[rs(x)].r ^= ;
T[x].r = ;//标记下传
}
}
void rotate(int x) {
int Y = T[x].f, R = T[Y].f, Yson = ident(x), Rson = ident(Y);
int B = T[x].ch[Yson ^ ];
//Q为什么要这样写 ******************************************** T[x].f = R;
if(!IsRoot(Y))
connect(x, R, Rson);
//这里如果不判断y是否根节点,那么当y是根节点的时候,0节点的儿子就会被更新为x
//这样x就永远不能被判断为根节点,也就会无限循环下去了
//但是这里不更新x的父亲的话就会出现无限递归的情况
connect(B, Y, Yson);
connect(Y, x, Yson ^ );
update(Y); update(x);
}
int st[MAXN];
void splay(int x) {
int y = x, top = ;
st[++top] = y;
while(!IsRoot(y)) st[++top] = y = fa(y);
while(top) pushdown(st[top--]);
//因为在旋转的时候不会处理标记,所以splay之前应该下传所有标记
for(int y = fa(x); !IsRoot(x); rotate(x), y = fa(x))//只要不是根就转
if(!IsRoot(y))
rotate( ident(x) == ident(y) ? x : y );
}
void access(int x) {//访问x节点
for(int y = ; x; x = fa(y = x))
splay(x), rs(x) = y, update(x);
//首先把x splay到所在平衡树的根,这样可以保证它的右孩子就是在原树中对应的重链(右孩子深度比它大)
//y是splay中x的儿子,把x的右儿子改成y,也就是把x和y之间的边变成实边
//更改了节点顺序,需要update
}
void makeroot(int x) {//把x改为原树的根节点
access(x);
splay(x);
T[x].r ^= ;
pushdown(x);
//首先访问一下x,再把x转到根,
//注意在access的时候都是连接的右儿子,这样会破坏顺序,因此我们需要将左右儿子翻转
}
int findroot(int x) {//找到x在原树中的根节点
access(x);splay(x);
while(ls(x)) x = ls(x);//找到深度最小的点即为根节点
return x;
}
void split(int x, int y) {
makeroot(x);//首先把x置为根节点
access(y); splay(y);
//然后访问一下y,再把y转到根节点,这样y维护的就是x - y 路径上的xor
}
void link(int x, int y) {
makeroot(x);//把x置为根节点
if(findroot(y) != x ) fa(x) = y;
//如果x与y不在同一个splay中,就把y置为x的父亲
//因为不能判断x与y的深度,因此在这里不用更新y的儿子
}
void cut(int x, int y) {
makeroot(x);
if(findroot(y) == x && fa(x) == y && !rs(x)) {
fa(x) = T[y].ch[] = ;
update(y);
}
//注意findroot(y)之后,y会成为根节点
//对于第三个判断
//可以构造出这样的树
// x
// fuck
// y
//在splay中是这样的
// y
//x
// fuck
//这样很显然x与y是不相连的
}
int main()
{
#ifdef WIN32
freopen("a.in","r",stdin);
//freopen("a.out","w",stdout);
#else
#endif
int N = read(), M = read();
for(int i = ; i <= N; i++) v[i] = read();
for(int i = ; i <= M; i++) {
int opt = read(), x = read(), y = read();
if(opt == ) split(x, y), printf("%d\n",T[y].s);
else if(opt == ) link(x, y);
else if(opt == ) cut(x, y);
else if(opt == ) splay(x), v[x] = y;
}
return ;
}

洛谷P3690 【模板】Link Cut Tree (LCT)的更多相关文章

  1. 洛谷P3690 [模板] Link Cut Tree [LCT]

    题目传送门 Link Cut Tree 题目背景 动态树 题目描述 给定n个点以及每个点的权值,要你处理接下来的m个操作.操作有4种.操作从0到3编号.点从1到n编号. 0:后接两个整数(x,y),代 ...

  2. LCT总结——概念篇+洛谷P3690[模板]Link Cut Tree(动态树)(LCT,Splay)

    为了优化体验(其实是强迫症),蒟蒻把总结拆成了两篇,方便不同学习阶段的Dalao们切换. LCT总结--应用篇戳这里 概念.性质简述 首先介绍一下链剖分的概念(感谢laofu的讲课) 链剖分,是指一类 ...

  3. 洛谷.3690.[模板]Link Cut Tree(动态树)

    题目链接 LCT(良心总结) #include <cstdio> #include <cctype> #include <algorithm> #define gc ...

  4. BZOJ 3282 Link Cut Tree (LCT)

    题目大意:维护一个森林,支持边的断,连,修改某个点的权值,求树链所有点点权的异或和 洛谷P3690传送门 搞了一个下午终于明白了LCT的原理 #include <cstdio> #incl ...

  5. 模板Link Cut Tree (动态树)

    题目描述 给定N个点以及每个点的权值,要你处理接下来的M个操作.操作有4种.操作从0到3编号.点从1到N编号. 0:后接两个整数(x,y),代表询问从x到y的路径上的点的权值的xor和.保证x到y是联 ...

  6. 【刷题】洛谷 P3690 【模板】Link Cut Tree (动态树)

    题目背景 动态树 题目描述 给定n个点以及每个点的权值,要你处理接下来的m个操作.操作有4种.操作从0到3编号.点从1到n编号. 0:后接两个整数(x,y),代表询问从x到y的路径上的点的权值的xor ...

  7. Luogu 3690 Link Cut Tree

    Luogu 3690 Link Cut Tree \(LCT\) 模板题.可以参考讲解和这份码风(个人认为)良好的代码. 注意用 \(set\) 来维护实际图中两点是否有直接连边,否则无脑 \(Lin ...

  8. AC日记——【模板】Link Cut Tree 洛谷 P3690

    [模板]Link Cut Tree 思路: LCT模板: 代码: #include <bits/stdc++.h> using namespace std; #define maxn 30 ...

  9. 洛谷P3690 Link Cut Tree (模板)

    Link Cut Tree 刚开始写了个指针版..调了一天然后放弃了.. 最后还是学了黄学长的板子!! #include <bits/stdc++.h> #define INF 0x3f3 ...

  10. LuoguP3690 【模板】Link Cut Tree (动态树) LCT模板

    P3690 [模板]Link Cut Tree (动态树) 题目背景 动态树 题目描述 给定n个点以及每个点的权值,要你处理接下来的m个操作.操作有4种.操作从0到3编号.点从1到n编号. 0:后接两 ...

随机推荐

  1. 利用PIE实现全球云分布图的效果

    1.问题背景: 最近项目中获得了一份全球云分布图,客户要求把云显示在全球地图上,出现云的效果,如下图所示: [全球云分布图] [世界地图云示意图] 2.解决思路 咨询专业的业务人员,建议我测试下试试地 ...

  2. 微服务架构之spring cloud zipkin

    Spring Cloud Zipkin是微服务的链路跟踪组件,帮助详细了解一次request&response的总计时,及每个微服务的消耗时间.微服务名称.异常信息等等过程信息. (一) 版本 ...

  3. Redirect local emails to a remote email account

    My previous post is a guide for setting up exim4, an SMTP mail server, to use Gmail as a smarthost. ...

  4. volley3--Volley类

    Volley这个类,Volley作为整个框架的入口,其实就是创建了一个RequestQueue队列 public class Volley { /** * Default on-disk cache ...

  5. 基于PMBOK的项目管理知识体系

  6. spring事务的理解

    特性 一致性:业务处理要么都成功,要么都失败,不能部分成功不分失败 原子性:业务操作是由多个动作完成,这些动作不可分割,要么都执行,要么都不执行 隔离性:事务间之间要做隔离,不要互相影响 持久性:操作 ...

  7. 类型安全的EventHandlerList

    我们写一个类时,有时候会在同一个类上添加很多事件,事件很多的话,是不容易管理的,.NET提供的EventHandlerList可以辅助多个事件的管理,但不方便的地方是,它不是类型安全的,缺少类型安全, ...

  8. Linux下调节CPU使用的几种方法

    一,使用taskset充分利用多核cpu,让cpu的使用率均衡到每个cpu上 #taskset-p,    设定一个已存在的pid,而不是重新开启一个新任务-c,    指定一个处理,可以指定多个,以 ...

  9. 克隆对象__clone()方法

    有的时候我们需要在一个项目里面,使用两个或多个一样的对象,如果你使用“new”关键字重新创建对象的话,再赋值上相同的属性,这样做比较烦琐而且也容易出错,所以要根据一个对象完全克隆出一个一模一样的对象, ...

  10. Attempt to load Oracle client libraries threw BadImageFormatException. This problem will occur when running in 64 bit mode with the 32 bit Oracle client components installed.

    System.Data.OracleClient 已经过时了.微软不再支持它. 因此,我建议你为. NET 使用Oracle数据提供程序:ODP.Net. 你可以从以下位置下载: 版本:Release ...