首页 > 其他 > 详细

[Link-Cut-Tree]【学习笔记】

时间:2017-01-11 07:35:08      阅读:180      评论:0      收藏:0      [点我收藏+]

可以按照<Utopiosphere>的调唱出来 “Link-Cut ,Time doesn’t stop .Prepare your doubts ,Eat them up”

参考资料:

1.popoqqq课件

2.《QTREE 解法的一些研究 》

3.http://blog.csdn.net/clove_unique/article/details/50991804

 

【理论知识】

  • Link-Cut-Tree(简称LCT)是解决动态树类问题一种数据结构
  • Preferred Child:重儿子,重儿子与父亲节点在同一棵Splay中,一个节点最多只能有一个重儿子
  • Preferred Edge:重边,连接父亲节点和重儿子的边
  • Preferred Path :重链,由重边及重边连接的节点构成的链

 

Auxiliary Tree(辅助树)

  • 由一条重链上的所有节点所构成的Splay称作这条链的辅助树
  • 每个点的键值为这个点的深度,即这棵Splay的中序遍历是这条链从链顶到链底的所有节点构成的序列
  • 辅助树的根节点的父亲指向链顶的父亲节点,然而链顶的父亲节点的儿子并不指向辅助树的根节点
  • (也就是说父亲不认轻儿子只认重儿子,儿子都认父亲)

原树与辅助树的关系

  • 原树中的重链 -> 辅助树中两个节点位于同一棵Splay
  • 原树中的轻链 -> 辅助树中子节点所在Splay的根节点的father指向父节点
  • 注意原树与辅助树的结构并不相同
  • 辅助树的根节点≠原树的根节点
  • 辅助树中的father≠原树中的father

辅助树是不断变化的,重链和轻链不断变化

 

二【实现】

LCT用到的Splay和通常的还是有点不同,没有权值v,不进行查找操作,点编号就是原树的编号

因为是一个Splay森林,多条重链多个根,所以用isRoot(x)判断是否为根,判断isRoot(x)相当于判断x的父亲存不存在

rotate只是设置g的儿子时判断isRoot(f)就行了

splay需要pushDown了(因为没有kth了),也是判断isRoot(pa)

 

Access 

  • 将一个点与原先的重儿子切断,并使这个原树上点到根路径上的边全都变为重边
  • 所以 这个节点到根的路径上的所有节点形成了一棵Splay
  • 便于操作或查询节点到根路径上的所有节点

实现:不断把x splay到当前Atree的根,然后它的右子树就是重儿子了,修改;用y辅助

注意:Access后x不一定为这颗Splay的根,因为中途x变fa了

MakeRoot

  • 将x设为原树的根

实现:Access后splay到根,然后全在x的左子树上(权值是深度),区间翻转即可

FindRoot

  • 找x所在原树根,判连通性

实现:MakeRoot后不断往左找(不需要pushDown因为只是为了判连通性)

Link

实现:MakeRoot(x)然后t[x].fa=y

Cut

实现:MakeRoot(x)然后Access(y) splay(y) ,x就在y的左子树了,t[y].ch[0]=t[x].fa=0;

 

 

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
using namespace std;
#define pa t[x].fa
#define lc t[x].ch[0]
#define rc t[x].ch[1]
const int N=2e5+5;
inline int read(){
    char c=getchar();int x=0,f=1;
    while(c<0||c>9){if(c==-)f=-1;c=getchar();}
    while(c>=0&&c<=9){x=x*10+c-0;c=getchar();}
    return x*f;
}

int n,Q,x,y;
char s[3];
struct node{
    int ch[2],fa,rev,size,w;
}t[N];
inline void update(int x){t[x].size=t[lc].size+t[rc].size+t[x].w;}
inline int wh(int x){return t[pa].ch[1]==x;}
inline int isRoot(int x){return t[pa].ch[0]!=x&&t[pa].ch[1]!=x;}
inline void pushDown(int x){
    if(t[x].rev){
        t[lc].rev^=1;
        t[rc].rev^=1;
        swap(lc,rc);
        t[x].rev=0;
    }
}
inline void rotate(int x){
    int f=t[x].fa,g=t[f].fa,c=wh(x);
    if(!isRoot(f)) t[g].ch[wh(f)]=x;t[x].fa=g;
    t[f].ch[c]=t[x].ch[c^1];t[t[f].ch[c]].fa=f;
    t[x].ch[c^1]=f;t[f].fa=x;
    update(f);update(x);
}
int st[N],top;
inline void splay(int x){
    top=0;st[++top]=x;
    for(int i=x;!isRoot(i);i=t[i].fa)
        st[++top]=t[i].fa;
    for(int i=top;i>=1;i--) pushDown(st[i]);
    
    for(;!isRoot(x);rotate(x))
        if(!isRoot(pa)) rotate(wh(x)==wh(pa)?pa:x);
}
inline void Access(int x){
    int y=0;
    for(;x;y=x,x=pa){
        splay(x);
        rc=y;
    }
}
inline void MakeRoot(int x){
    Access(x);
    splay(x);
    t[x].rev^=1;
}
inline int FindRoot(int x){
    Access(x);
    splay(x);
    while(lc) x=lc;
    return x;
}
inline void Link(int x,int y){
    MakeRoot(x);
    t[x].fa=y;
    //splay(x);
}
inline void Cut(int x,int y){
    MakeRoot(x);
    Access(y);
    splay(y);
    t[y].ch[0]=t[x].fa=0;
}

int main(){
    n=read();Q=read();
    while(Q--){
        scanf("%s",s);x=read();y=read();
        if(s[0]==C) Link(x,y);
        else if(s[0]==D) Cut(x,y);
        else{
            if(FindRoot(x)==FindRoot(y)) puts("Yes");
            else puts("No");
        }
    }
}

 

[Link-Cut-Tree]【学习笔记】

原文:http://www.cnblogs.com/candy99/p/6271344.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!