luogu3690 【模板】 Link Cut Tree(动态树)
题目大意
给定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(动态树)的更多相关文章
- LCT总结——概念篇+洛谷P3690[模板]Link Cut Tree(动态树)(LCT,Splay)
为了优化体验(其实是强迫症),蒟蒻把总结拆成了两篇,方便不同学习阶段的Dalao们切换. LCT总结--应用篇戳这里 概念.性质简述 首先介绍一下链剖分的概念(感谢laofu的讲课) 链剖分,是指一类 ...
- 洛谷.3690.[模板]Link Cut Tree(动态树)
题目链接 LCT(良心总结) #include <cstdio> #include <cctype> #include <algorithm> #define gc ...
- Link Cut Tree 动态树 小结
动态树有些类似 树链剖分+并查集 的思想,是用splay维护的 lct的根是动态的,"轻重链"也是动态的,所以并没有真正的轻重链 动态树的操作核心是把你要把 修改/询问/... 等 ...
- LCT(link cut tree) 动态树
模板参考:https://blog.csdn.net/saramanda/article/details/55253627 综合各位大大博客后整理的模板: #include<iostream&g ...
- 洛谷P3690 Link Cut Tree (动态树)
干脆整个LCT模板吧. 缺个链上修改和子树操作,链上修改的话join(u,v)然后把v splay到树根再打个标记就好. 至于子树操作...以后有空的话再学(咕咕咕警告) #include<bi ...
- 洛谷P3690 [模板] Link Cut Tree [LCT]
题目传送门 Link Cut Tree 题目背景 动态树 题目描述 给定n个点以及每个点的权值,要你处理接下来的m个操作.操作有4种.操作从0到3编号.点从1到n编号. 0:后接两个整数(x,y),代 ...
- 模板Link Cut Tree (动态树)
题目描述 给定N个点以及每个点的权值,要你处理接下来的M个操作.操作有4种.操作从0到3编号.点从1到N编号. 0:后接两个整数(x,y),代表询问从x到y的路径上的点的权值的xor和.保证x到y是联 ...
- 【刷题】洛谷 P3690 【模板】Link Cut Tree (动态树)
题目背景 动态树 题目描述 给定n个点以及每个点的权值,要你处理接下来的m个操作.操作有4种.操作从0到3编号.点从1到n编号. 0:后接两个整数(x,y),代表询问从x到y的路径上的点的权值的xor ...
- P3690 【模板】Link Cut Tree (动态树)
P3690 [模板]Link Cut Tree (动态树) 认父不认子的lct 注意:不 要 把 $fa[x]$和$nrt(x)$ 混 在 一 起 ! #include<cstdio> v ...
- LuoguP3690 【模板】Link Cut Tree (动态树) LCT模板
P3690 [模板]Link Cut Tree (动态树) 题目背景 动态树 题目描述 给定n个点以及每个点的权值,要你处理接下来的m个操作.操作有4种.操作从0到3编号.点从1到n编号. 0:后接两 ...
随机推荐
- POJ 1985 求树的直径 两边搜OR DP
Cow Marathon Description After hearing about the epidemic of obesity in the USA, Farmer John wants h ...
- layui confirm
layer.confirm('是否要删除信息!', { btn: ['确定', '取消'] }, function (index, layero) { //移除元素 $("#tr" ...
- python 从Excel中取值
import openpyxl from openpyxl import load_workbook def open_file(file_path): workbook = load_workboo ...
- python-selenium,关于页面滑动
第一种: #滑到底部 js="var q=document.documentElement.scrollTop=100000" driver.execut_script(js) 目 ...
- Selenium3+python自动化 -JS处理滚动条
selenium并不是万能的,有时候页面上操作无法实现的,这时候就需要借助JS来完成了. 常见场景: 当页面上的元素超过一屏后,想操作屏幕下方的元素,是不能直接定位到,会报元素不可见的. 这时候需要借 ...
- encodeURI和encodeURIComponent的区别?
encodeURI方法不会对下列字符编码 ASCII字母.数字.~!@#$&*()=:/,;?+' encodeURIComponent方法不会对下列字符编码 ASCII字母.数字.~!*() ...
- Python学习【第1篇】:环境配置
1. 下载安装包 https://www.python.org/ftp/python/2.7.14/python-2.7.14.amd64.msi # 2.7安装包 https://www. ...
- 爬虫系列(十) 用requests和xpath爬取豆瓣电影
这篇文章我们将使用 requests 和 xpath 爬取豆瓣电影 Top250,下面先贴上最终的效果图: 1.网页分析 (1)分析 URL 规律 我们首先使用 Chrome 浏览器打开 豆瓣电影 T ...
- jupyter记事本的安装和简单应用
1.概述 jupyter记事本是一个基于Web的前端,被分成单个的代码块或单元.根据需要,单元可以单独运行,也可以一次全部运行.这使得我们可以运行某个场景,看到输出结果,然后回到代码,根据输出结果对代 ...
- (33)Spring Boot 监控和管理生产环境【从零开始学Spring Boot】
[本文章是否对你有用以及是否有好的建议,请留言] spring-boot-actuator模块提供了一个监控和管理生产环境的模块,可以使用http.jmx.ssh.telnet等拉管理和监控应用.审计 ...