题目大意

给定n个点以及每个点的权值,要你处理接下来的m个操作。操作有4种。操作从0到3编号。点从1到n编号。
0.询问从x到y的路径上的点的权值的xor和。保证x到y是联通的。
1.代表连接x到y,若x到y已经联通则无需连接。
2.后接两个整数(x,y),代表删除边(x,y),不保证边(x,y)存在。
3.将点x上的权值变成y。

总体思路

在动态树中,结点是可以通过Link和Cut进行变换的,对于维护静态树的树链剖分可就不管用了。此时如何效率高地对多个点的值进行存储处理呢?如果可以利用上结点可以灵活地转动的splay树,这样就可以通过存储每个点的子树中的值的方式满足一个点对多个点的值进行存储了呀!

回顾Splay树,其实质上维护的是一个值递增的数列,每一棵子树维护的都是数列中连续的一段区间。那么在这个原图中,对于每一条链,上面的节点的深度根据父子关系都是递增的。如果我们把这条链上的节点按照深度排成一排,这也是一个数列,所以可以用Splay树来解决。

关于这棵splay树

splay树维护的是原图中的一条链,节点的key值为原图中节点的深度,每个节点维护其子树的Xor和。每个子树都维护一段子链。(注意,splay树中的排列方式与其在原图中具体谁与谁相邻无关)因此,splay树根节点的Xor值便是整条链的Xor和,它的父节点是连接splay树所维护的链的某个节点(具体为splay树最靠左的节点)的原图中的父节点。

既然这叫做动态树,所以树可以是不断变换的。如果我们要对两点间的路径进行查询,只要把一个点放在splay的树根上且没有右孩子(位于所在链链顶),另一个点放在splay树所维护的链的链底,这样就可以知道整条链上的值了。

基本操作

Access

Access(Node *cur)是生成结点cur到顶端Splay树根的一条链,需要用到链的断开与连接。具体操作就是从下往上找。对于一个splay树中的结点cur,将cur通过Splay使其成为当前splay树的树根,然后将当前这个树根cur的右孩子断开(此时cur就成为了链底),将其设为之前找到的Splay树的树根prev(一开始prev是个NULL,所以cur没有右孩子),并更新cur存储的Xor和,然后cur变为其父亲(也就是cur所在链的链顶的父亲),prev变为cur,由此不断循环,直到cur成为原图树根所在的Splay树的树根。

“经常用到的操作”Access后Splay

首先Access(cur),然后Splay(cur)。此时cur成为了顶端Splay树根。因为原来原图的树根在当前splay树的最左侧,cur在splay树的树根,还没有右孩子,所以说这个操作使得原图中的树根成为了链底,cur成为了链顶。

MakeRoot

MakeRoot(Node *cur)是将结点cur设为原图中的根节点。

“经常用到的操作”后,顶端Splay树上的节点里原根越近,离新根就越远。所以将顶端Splay树整体翻转即可。

关于翻转

翻转就是将自己的左右孩子交换,然后将自己的翻转标记取反。每次Splay之前都要PushDown,递归到当前Splay树的根节点,从根节点开始,如果当前结点有有Rev标记,则将当前结点的孩子的左右孩子交换。

MakePath

MakePath(Node *from, Node *to)是将from和to放到一个链内,并使to成为链顶,from成为链底。首先MakeRoot(from),然后“经常用到的操作”to即可。

FindRoot

FindRoot(Node *cur)指以cur为起点,找到原图的树根。“经常用到的操作”cur,然后不断找左孩子即可。

应用操作

Query

Query(Node *from, Node *to)是要查询from到to的路径的Xor和。MakePath(from, to)后,因为splay树根节点的Xor值便是整条链的Xor和,所以to的Xor值即为所求。

Link

Link(Node *from, Node *to)是要连接from和to。首先MakeRoot(from),然后如果FindRoot(to)!=from,则将from的Father设成to即可。(注意必须是MakeRoot(from),而不是“经常用到的操作”from,因为这样并没有给father设置,而是给链的根设置了)。

Cut

Cut(Node *from, Node *to)是要剪掉from和to。首先MakePath(from, to),如果from和to已经连接,则两点间的路径就是两点的边,又因为MakePath后to是链顶,所以如果to->LeftSon==from,再Cut。

Modify

Modify(Node *cur)是要修改cur的值。先把cur Splay到其所在Splay树的树根,然后改cur的值并Refresh。这样避免了对整个树进行更新。

#include <cstdio>
#include <cstring>
#include <cassert>
#include <algorithm>
using namespace std; const int MAX_NODE = 300010;
#define LOOP(i, n) for(int i=1; i<=n; i++) struct LctTree
{
private:
struct Node
{
Node *Father, *LeftSon, *RightSon;
int Weight, Xor, Id;
bool ReverseFlag; Node()
{
Weight = Xor = 0;
LeftSon = RightSon = Father = NULL;
ReverseFlag = false;
} Node(int weight) :Weight(weight), Xor(weight)
{
LeftSon = RightSon = Father = NULL;
ReverseFlag = false;
} void Reverse()
{
swap(LeftSon, RightSon);
ReverseFlag = !ReverseFlag;
} void PushDown()
{
if (ReverseFlag)
{
if (LeftSon)//不要忘了判断
LeftSon->Reverse();
if (RightSon)//不要忘了判断
RightSon->Reverse();
ReverseFlag = false;
}
} bool IsRoot()
{
return Father == NULL || (Father->LeftSon != this && Father->RightSon != this);
} bool IsLeftSon()
{
return Father->LeftSon == this;
} void Refresh()
{
Xor = (LeftSon ? LeftSon->Xor : 0) ^ (RightSon ? RightSon->Xor : 0) ^ Weight;
}
}_nodes[MAX_NODE]; struct SplayTree
{
private:
Node *InnerRoot; void PushDown(Node *cur)
{
if (!cur->IsRoot())
PushDown(cur->Father);
cur->PushDown();
} void Rotate(Node *cur)
{
Node *gfa = cur->Father->Father;
Node **gfaSon = cur->Father->IsRoot() ? &InnerRoot : (cur->Father->IsLeftSon() ? &gfa->LeftSon : &gfa->RightSon);//TODO
Node **faSon = cur->IsLeftSon() ? &cur->Father->LeftSon : &cur->Father->RightSon;
Node **curSon = cur->IsLeftSon() ? &cur->RightSon : &cur->LeftSon;
*faSon = *curSon;
if (*faSon)
(*faSon)->Father = cur->Father;
*curSon = cur->Father;
(*curSon)->Father = cur;
*gfaSon = cur;
(*gfaSon)->Father = gfa;
(*curSon)->Refresh();
cur->Refresh();
} public:
void Splay(Node *cur)
{
PushDown(cur);
while (!cur->IsRoot())
{
if (!cur->Father->IsRoot())
Rotate(cur->Father->IsLeftSon() == cur->IsLeftSon() ? cur->Father : cur);
Rotate(cur);
}
}
}AuTree; void Access(Node *cur)
{
Node *prev = NULL;
while (cur)//是cur,不是cur->IsRoot()。
{
AuTree.Splay(cur);
cur->RightSon = prev;
cur->Refresh();
prev = cur;
cur = cur->Father;
}
} Node *FindRoot(Node *cur)
{
Access(cur);
AuTree.Splay(cur);
while (cur->LeftSon)
cur = cur->LeftSon;
return cur;
} void MakeRoot(Node *cur)
{
Access(cur);
AuTree.Splay(cur);
cur->Reverse();
} void MakePath(Node *from, Node *to)
{
MakeRoot(from);
Access(to);
AuTree.Splay(to);
} int Query(Node *from, Node *to)
{
MakePath(from, to);
return to->Xor;
} void Link(Node *from, Node *to)
{
MakeRoot(from);
if (FindRoot(to) != from)
from->Father = to;
} void Cut(Node *from, Node *to)
{
MakePath(from, to);
if (to->LeftSon == from)
from->Father = to->LeftSon = NULL;
} void Modify(Node *cur, int w)
{
Access(cur);
AuTree.Splay(cur);
cur->Weight = w;
cur->Refresh();
} public:
void SetNode(int id, int weight)
{
Node *cur = _nodes + id;
cur->Id = id;
cur->Weight = cur->Xor = weight;//易忘点:cur->Xor
} int Query(int u, int v)
{
return Query(_nodes + u, _nodes + v);
} void Link(int u, int v)
{
Link(_nodes + u, _nodes + v);
} void Cut(int u, int v)
{
Cut(_nodes + u, _nodes + v);//TODO//别写成Link了
} void Modify(int u, int w)
{
Modify(_nodes + u, w);
}
}g; int main()
{
int nodeCnt, opCnt, w, op, u, v;
scanf("%d%d", &nodeCnt, &opCnt);
LOOP(i, nodeCnt)
{
scanf("%d", &w);
g.SetNode(i, w);
}
while (opCnt--)
{
scanf("%d", &op);
switch (op)
{
case 0://Query
scanf("%d%d", &u, &v);
printf("%d\n", g.Query(u, v));
break;
case 1://Link
scanf("%d%d", &u, &v);
g.Link(u, v);
break;
case 2://Cut
scanf("%d%d", &u, &v);
g.Cut(u, v);
break;
case 3://Modify
scanf("%d%d", &u, &w);
g.Modify(u, w);
break;
}
}
return 0;
}

  

luogu3690 【模板】 Link Cut Tree(动态树)的更多相关文章

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

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

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

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

  3. Link Cut Tree 动态树 小结

    动态树有些类似 树链剖分+并查集 的思想,是用splay维护的 lct的根是动态的,"轻重链"也是动态的,所以并没有真正的轻重链 动态树的操作核心是把你要把 修改/询问/... 等 ...

  4. LCT(link cut tree) 动态树

    模板参考:https://blog.csdn.net/saramanda/article/details/55253627 综合各位大大博客后整理的模板: #include<iostream&g ...

  5. 洛谷P3690 Link Cut Tree (动态树)

    干脆整个LCT模板吧. 缺个链上修改和子树操作,链上修改的话join(u,v)然后把v splay到树根再打个标记就好. 至于子树操作...以后有空的话再学(咕咕咕警告) #include<bi ...

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

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

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

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

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

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

  9. P3690 【模板】Link Cut Tree (动态树)

    P3690 [模板]Link Cut Tree (动态树) 认父不认子的lct 注意:不 要 把 $fa[x]$和$nrt(x)$ 混 在 一 起 ! #include<cstdio> v ...

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

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

随机推荐

  1. MySQL 数据的增删改查

    一.数据库的增删改 一. 在MySQL管理软件中,可以通过SQL语句中的DML语言来实现数据的操作,包括 1.使用INSERT实现数据的插入 2.UPDATE实现数据的更新 3.使用DELETE实现数 ...

  2. 5.23Java各种对象(PO,BO,VO,DTO,POJO,DAO,Entity,JavaBean,JavaBeans)的区分

    作者:https://www.cnblogs.com/lyjin/p/6389349.html PO:持久对象(persistent object):---po就是在Object/Relation M ...

  3. Laravel5.1学习笔记7 视图

    视图 (View) 基本用法 传递数据到视图 在多个视图中分享数据 视图组件   #基本用法 视图里面包含了你应用程序所提供的 HTML 代码,并且提供一个简单的方式来分离控制器和网页呈现上的逻辑.视 ...

  4. Asp.net MVC4 Step by Step (3)-数据验证

    ASP.NET MVC把数据验证集成到了请求处理过程中,控制器操作可以通过查询ModelState 来检查请求是否有效, 下面判断了ModelState的有效性后进行“保存或返回”操作.   [Htt ...

  5. VS2012快捷操作功能

    VS2003用了6年,感情深厚,最近换工作刚刚接触VS2010,使用一个月感觉VS2010在人性化方面的功能实在是太强悍了,大大提高了写代码的效率,就如同魔兽世界里的快捷键操作一样,左手抚键右手摸鼠, ...

  6. 图像局部显著性—点特征(SIFT为例)

    基于古老的Marr视觉理论,视觉识别和场景重建的基础即第一阶段为局部显著性探测.探测到的主要特征为直觉上可刺激底层视觉的局部显著性--特征点.特征线.特征块. SalientDetection 已经好 ...

  7. spring中的prop、set、list、map

    props.set.list.map这些事spring配置文件中很常见的标签,下面说下各自的适用场合. props:用于键值对,建和值都为string类型. <property name=&qu ...

  8. 【MySQL】ERROR 1005: Can't create table (errno: 150)的错误解决办法

    在mysql 中建立引用约束的时候会出现MySQL ERROR 1005: Can't create table (errno: 150)的错误信息结果是不能建立 引用约束. 出现问题的大致情况 1. ...

  9. Coreldraw软件反盗版提示x8有优惠活动 cdr x8提示盗版怎么办?

    CorelDRAW X8装不上,我的悲伤有这么大,或者比这还大一点...♥♥♥如果你遇到这样的断了网,卸了装,装了卸,然后再安装的...╮(-_-)╭这样的保存和另存为都点不了,不敢关电脑的亦或是这样 ...

  10. ivew使用星星评分

    这组件好像有问题,不知道是我们项目环境造成的还是什么,初始化半星不能正常显示,显示的全星. 1.template <div style="display:inline-block;ma ...