Link-cut-tree 学习记录 & hdu4010
网上的lct一抓一大把,所以我也不再写什么讲解了,只写一写自己的看法.
Link-cut-tree 是用于维护动态树的一种数据结构
所谓动态树就是一片存在边的添加与删除的森林中的一棵树
所以我们要快速处理加边和删边
关于具体的Preferred Child和Preferred Path还有Preferred Edge什么的...就不多说了
不过关于link-cut-tree还有比较重要,刚开始易混淆的地方:
- LCT实际上维护的是两棵树,一棵是原树,另一棵是辅助树.其中原树就是我们要维护的树,而辅助树则是我们根据Preferred Path而维护的Splay森林.即每条Preferred Path都是一棵Splay.
- 所以我们有:
- 原树与辅助树的结构并不相同
- 辅助树的根节点不等于原树的根节点
- 辅助树中的father不等于原树中的father
对LCT的上述性质比较了解后,这里来介绍一下LCT的基本操作.
基本操作
Access(u) :
- 将原树上u到根的路径全部变为Prefered Edge,也就是操作之后将会出现一条同时包括原树的根与原树上节点u的Prefferd Path.
- 将在原树上到根所经过的所有辅助树的节点取出,构成一棵新的Splay.也就是说,这时原树中的根与原树着的u共处于同一棵辅助树中.
inline Node* Access(Node *u){
for(Node *v=null;u != null;v=u,u=u->fa)
splay(u),u->ch[1] = v,u->update();
return u;
}
findRoot(u) :
- 找到原树中u所在树的根节点(不要忘了我们维护的是一片森林)
- 我们知道根节点的深度一定最小,所以我们Access(u)后,u一定与原树中的根节点同处于一棵Splay(辅助树)中.所以我们知道根节点一定是u所在splay的最左节点.所以我们splay(u)然后找到最靠左的节点即可.
- 注意 : 为了保证均摊复杂度为\(O(logn)\)这里仍需要对找到的根rt进行Splay
inline Node* getRt(Node *u){
Access(u);splay(u);
while(u->ch[0] != null) u = u->ch[0];
splay(u);return u;
}
makrRoot(u) :
- 将原树中的u作为原树的根节点,
- 由于原树与辅助树的树形结构并不相同,这里不能直接Access(u),splay(u)就完事.由于splay中是按照deep为关键字排序的,所以在辅助树中无论以那个节点为根,都不会改变原树中的根,因为Splay过程中节点的相对位置不会进行变化,而根的dep最小,一定时时刻刻处于最左端.所以我们可以在Access(u),splay(u)后对u打上翻转标记,表示让u所在的辅助树的根节点进行反转.
我们来分析一下上述操作的正确性:
首先我们知道:
- 所有深度大于u的节点一定都不会被存放在这棵辅助树中
所以我们就发现: Splay(u)后一定不存在任何一个节点在u的右侧
所以现在我们只考虑u左面接上了一条链的情况.(其他情况一定可以转化成链)
这时候我们发现如果我们选择以u作为根,那么这条链上节点的深度关系会中心对称地变化
所以我们在这条链上打上翻转标记即可.
inline void makeRt(Node *u){
Access(u);splay(u);u->tag ^= 1;
}
link(u,v) :
- 将u接到v的下面
- 实现这个操作有两一种方法:
- 方法一: makeroot(u),u->fa = v;
- 方法二: Access(u),splay(u),u->fa = v;
- 不要管第二种方法了,明显是不对的... ...
这个操作的问题应该不大...
inline void link(Node *u,Node *v){
makeRt(u);u->fa = v;
}
cut(u,v)
- 删除u与v之间的边.
- makeRoot(u),Access(v),splay(v),v->ch[0] = v->ch[0]->fa = 0;
inline void cut(Node *u,Node *v){
makeRt(u);Access(v);splay(v);
v->ch[0] = v->ch[0]->fa = null;
v->update();
}
如果是删除u与其father的连边呢?
- Access(u),splay(u),u->ch[0] = u->ch[0]->fa = 0;
其他操作
get(u,v):
- 取出原树上u->v这一条链并恰好将其存于一棵辅助树中,并返回这棵辅助树的根节点.
- makrRoot(u),Access(v),splay(v) 此时v即为所求
inline Node* get(Node *u,Node *v){
makeRt(u);Access(v);splay(v);
return v;
}
lca(rt,u,v):
- 求出以rt为根时的u和v的lca(最近公共祖先)
- makeroot(rt),Access(u),Access(v),此时Access(v)范围值即为所求
inline Node* lca(Node *rt,Node *u,Node *v){
makeRt(rt);Access(u);return Access(v);
}
更多操作等会会了再写上来
模板:
hdu 4010 Link-Cut-Tree
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
typedef long long ll;
inline void read(int &x){
x=0;char ch;bool flag = false;
while(ch=getchar(),ch<'!');if(ch == '-') ch=getchar(),flag = true;
while(x=10*x+ch-'0',ch=getchar(),ch>'!');if(flag) x=-x;
}
const int maxn = 600010;
struct Node{
Node *ch[2],*fa;
int w,mx,lazy,tag;
void update();
}*null,*it,mem[maxn];
void Node::update(){
mx = max(max(ch[0]->mx,ch[1]->mx),w);
}
inline void init(){
it = mem;null = it++;
null->ch[0] = null->ch[1] = null->fa = null;
null->w = null->mx = null->lazy = null->tag = 0;
}
inline void newNode(int val){
Node *p = it++;p->w = p->mx = val;
p->ch[0] = p->ch[1] = p->fa = null;
p->lazy = p->tag = 0;
}
inline void push_down(Node *p){
if(p == null) return;
if(p->lazy != 0){
if(p->ch[0] != null){
p->ch[0]->w += p->lazy;
p->ch[0]->mx += p->lazy;
p->ch[0]->lazy += p->lazy;
}
if(p->ch[1] != null){
p->ch[1]->w += p->lazy;
p->ch[1]->mx += p->lazy;
p->ch[1]->lazy += p->lazy;
}
p->lazy = 0;
}
if(p->tag != 0){
if(p->ch[0] != null) p->ch[0]->tag ^= 1;
if(p->ch[1] != null) p->ch[1]->tag ^= 1;
swap(p->ch[0],p->ch[1]);
p->tag = 0;
}
}
inline void rotate(Node *p,Node *x){
int k = p == x->ch[1];
Node *y = p->ch[k^1],*z = x->fa;
if(z->ch[0] == x) z->ch[0] = p;
if(z->ch[1] == x) z->ch[1] = p;
if(y != null) y->fa = x;
p->fa = z;p->ch[k^1] = x;
x->fa = p;x->ch[k] = y;
x->update();p->update();
}
inline bool isroot(Node *p){
return (p->fa->ch[0] != p && p->fa->ch[1] != p);
}
Node* sta[maxn];int top;
inline void splay(Node *p){
push_down(p);
while(!isroot(p)){
Node *x = p->fa,*y = x->fa;
push_down(y);push_down(x);push_down(p);
if(isroot(x)) rotate(p,x);
else if((p == x->ch[0])^(x == y->ch[0])) rotate(p,x),rotate(p,y);
else rotate(x,y),rotate(p,x);
}p->update();
}
inline Node* Access(Node *u){
for(Node *v=null;u != null;v=u,u=u->fa)
splay(u),u->ch[1] = v,u->update();
return u;
}
inline void makeRt(Node *u){
Access(u);splay(u);u->tag ^= 1;
}
inline void link(Node *u,Node *v){
makeRt(u);u->fa = v;
}
inline void cut(Node *u,Node *v){
makeRt(u);Access(v);splay(v);
v->ch[0] = v->ch[0]->fa = null;
v->update();
}
inline Node* getRt(Node *u){
Access(u);splay(u);
while(u->ch[0] != null) u = u->ch[0];
splay(u);return u;
}
inline void inc(Node *u,Node *v,int w){
makeRt(u);Access(v);splay(v);
v->lazy += w;v->w += w;v->mx += w;
}
inline int query(Node *u,Node *v){
makeRt(u);Access(v);splay(v);
return v->mx;
}
int a[maxn],b[maxn];
int main(){
int n;
while(scanf("%d",&n) != EOF){
init();
for(int i=1;i<n;++i) read(a[i]),read(b[i]);
for(int i=1,x;i<=n;++i){
read(x),newNode(x);
}
for(int i=1;i<n;++i) link(mem+a[i],mem+b[i]);
int m;read(m);
int op,x,y,z;
while(m--){
read(op);read(x);read(y);
if(op == 1){
if(getRt(mem+x) == getRt(mem+y)) puts("-1");
else link(mem+x,mem+y);
}else if(op == 2){
if(getRt(mem+x) != getRt(mem+y) || x == y) puts("-1");
else cut(mem+x,mem+y);
}else if(op == 3){
z = x;x = y;read(y);
if(getRt(mem+x) != getRt(mem+y)) puts("-1");
else inc(mem+x,mem+y,z);
}else if(op == 4){
if(getRt(mem+x) != getRt(mem+y)) puts("-1");
else printf("%d\n",query(mem+x,mem+y));
}
}puts("");
}
getchar();getchar();
return 0;
}
Link-cut-tree 学习记录 & hdu4010的更多相关文章
- Link Cut Tree学习笔记
从这里开始 动态树问题和Link Cut Tree 一些定义 access操作 换根操作 link和cut操作 时间复杂度证明 Link Cut Tree维护链上信息 Link Cut Tree维护子 ...
- 学习笔记:Link Cut Tree
模板题 原理 类似树链剖分对重儿子/长儿子剖分,Link Cut Tree 也做的是类似的链剖分. 每个节点选出 \(0 / 1\) 个儿子作为实儿子,剩下是虚儿子.对应的边是实边/虚边,虚实时可以进 ...
- link cut tree 入门
鉴于最近写bzoj还有51nod都出现写不动的现象,决定学习一波厉害的算法/数据结构. link cut tree:研究popoqqq那个神ppt. bzoj1036:维护access操作就可以了. ...
- Link/cut Tree
Link/cut Tree 一棵link/cut tree是一种用以表示一个森林,一个有根树集合的数据结构.它提供以下操作: 向森林中加入一棵只有一个点的树. 将一个点及其子树从其所在的树上断开. 将 ...
- LCT总结——概念篇+洛谷P3690[模板]Link Cut Tree(动态树)(LCT,Splay)
为了优化体验(其实是强迫症),蒟蒻把总结拆成了两篇,方便不同学习阶段的Dalao们切换. LCT总结--应用篇戳这里 概念.性质简述 首先介绍一下链剖分的概念(感谢laofu的讲课) 链剖分,是指一类 ...
- Link Cut Tree 总结
Link-Cut-Tree Tags:数据结构 ##更好阅读体验:https://www.zybuluo.com/xzyxzy/note/1027479 一.概述 \(LCT\),动态树的一种,又可以 ...
- 脑洞大开加偏执人格——可持久化treap版的Link Cut Tree
一直没有点动态树这个科技树,因为听说只能用Splay,用Treap的话多一个log.有一天脑洞大开,想到也许Treap也能从底向上Split.仔细思考了一下,发现翻转标记不好写,再仔细思考了一下,发现 ...
- Codeforces Round #339 (Div. 2) A. Link/Cut Tree 水题
A. Link/Cut Tree 题目连接: http://www.codeforces.com/contest/614/problem/A Description Programmer Rostis ...
- 洛谷P3690 Link Cut Tree (模板)
Link Cut Tree 刚开始写了个指针版..调了一天然后放弃了.. 最后还是学了黄学长的板子!! #include <bits/stdc++.h> #define INF 0x3f3 ...
- bzoj2049 [Sdoi2008]Cave 洞穴勘测 link cut tree入门
link cut tree入门题 首先说明本人只会写自底向上的数组版(都说了不写指针.不写自顶向下QAQ……) 突然发现link cut tree不难写... 说一下各个函数作用: bool isro ...
随机推荐
- Centos 初始化服务器防火墙没有启动找不到/etc/sysconfig/iptables
个人博客:https://blog.sharedata.info/ 具体步骤:添加规则然后重启防火墙自动生成防火墙文件1.iptables -P OUTPUT ACCEPT #添加出规则2.servi ...
- 关于使用Tomcat服务器出现413错误的解决办法(Request Entity Too Large)
解决的办法: 修改tomcat的配置文件C:/MinyooCMS/tomcat/conf/server.xml(或者安装在D盘文件路径是D: /MinyooCMS/tomcat/conf/server ...
- Black And White(DFS+剪枝)
Black And White Time Limit: 2000/2000 MS (Java/Others) Memory Limit: 512000/512000 K (Java/Others ...
- [原创]关于absolute、relative和float的一些思考
absolute: 元素完全脱离文档流,不占文档流的位置,不使用top.left等属性时,仍然在原文档流位置上(但是不在文档流中,也不占用位置),设置了top.left等之后,向上寻找到第一个非sta ...
- 【python】-- 元组、字典
元组 元组其实跟列表差不多,也是存一组数,只不是它一旦创建,便不能再修改,所以又叫只读列表 用途:一般情况下用于自己写的程序能存下数据,但是又希望这些数据不会被改变,比如:数据库连接信息等 1.访问元 ...
- 5.Django数据库配置
Django默认支持sqlite.mysql.oracle.postgresql数据库,像db2和sqlserver需要安装第三方的支持 配置Django数据库:\hello_django\hello ...
- (转)Web Service和WCF的到底有什么区别
[1]Web Service:严格来说是行业标准,也就是Web Service 规范,也称作WS-*规范,既不是框架,也不是技术. 它有一套完成的规范体系标准,而且在持续不断的更新完善中. 它使用XM ...
- Java的接口和抽象类(转发:http://www.importnew.com/18780.html)
深入理解Java的接口和抽象类 对于面向对象编程来说,抽象是它的一大特征之一.在Java中,可以通过两种形式来体现OOP的抽象:接口和抽象类.这两者有太多相似的地方,又有太多不同的地方.很多人在初学的 ...
- python基础11 ---函数模块1
函数模块 一.函数模块的作用(为什么要有函数模块) 1.函数模块可以减少代码量 2.函数模块方便阅读 3.函数模块维护性强二.函数模块的本质以及调用方法 1.函数模块的本质就是一个.py结尾的文件,该 ...
- Yii2 如何实现表单事件之 Ajax 提交
前言 Yii2 现在使用 JS 都必须要注册代码了. 要实现 Ajax 提交,有两种方法.一是直接在 ActiveForm 调用 beforeSubmit 参数,但是个人认为这样没有很好的把 JS 和 ...