欢迎来到endl的博客hhh☀☾☽♡♥

浏览器标题切换
把博客园图标替换成自己的图标
把博客园图标替换成自己的图标end

LCT(link cut tree)大法好

新手推荐阅读:LCT总结——概念篇+洛谷P3690[模板]Link Cut Tree(动态树)(LCT,Splay)题解 P3690 【【模板】Link Cut Tree (动态树)】


 

Acwing算法进阶课笔记

动态树

虚边 实边
Splay维护所有的实边路径
其中序遍历就是要维护的路径(从上到下)
1. 本质上是维护所有实边,用splay中的后继与前驱来维护原树中的父子关系
2. 虚边:splay的根节点来维护

Access(x):建立一条从根节点到x的实边路径

IL void access(int x) {//打通从根节点到x的路径,x最深
    for(R y=0; x; x=fa(y=x)) {
        splay(x),rs(x)=y,pushup(x);
    }
}

Make_root(x):将x变成根节点

IL void makeroot(int x) {//把x变为原树的根
    access(x),splay(x),Rev(x);
}

Find_root(x):找到x所在的根节点

IL int findroot(int x) {//找到x的原树的根
    access(x),splay(x);
    while(ls(x)) pushdown(x),x=ls(x);
    return x;
}

Spilt(x,y):将x到y的路径变成实边路径

IL void split(int x,int y) {//y维护x-y路径上的信息
    makeroot(x),access(y),splay(y);
}

Link(x,y):若x,y不连通,则加入(x,y)这条边

IL void link(int x,int y) {
    makeroot(x);if(findroot(y)!=x)  fa(x)=y;
}

Cut(x,y):若x,y之间有边,则删掉该边

IL void cut(int x,int y) {
    split(x,y);
    if(fa(x)==y&&rs(x)==0) fa(x)=ls(y)=0,pushup(y);
}

Isroot(x):判断x是否是所在splay的根节点

IL int nroot(int x) //返回1说明x不是根,返回0说明x是根 
{return ls(fa(x))==x||rs(fa(x))==x;}

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

萌新写代码~码风跟喻队学的

  1 #include<bits/stdc++.h>
  2 #define IL inline
  3 #define R register int
  4 #define ls(x) a[x].ch[0]
  5 #define rs(x) a[x].ch[1]
  6 #define fa(x) a[x].fa
  7 
  8 using namespace std;
  9 const int N=1e5+5,inf=0x3f3f3f3f;
 10 
 11 IL int read() {
 12     int f=1;
 13     char ch;
 14     while((ch=getchar())<'0'||ch>'9') if(ch=='-') f=-1;
 15     int res=ch-'0';
 16     while((ch=getchar())>='0'&&ch<='9') res=res*10+ch-'0';
 17     return res*f;
 18 }
 19 
 20 int n,m;
 21 struct hh {
 22     int ch[2],fa,val,rev,sum;
 23 } a[N];
 24 
 25 IL int chk(int x) {return x==rs(fa(x));}
 26 IL void Rev(int x) {swap(ls(x),rs(x));a[x].rev^=1;}
 27 IL void pushup(int x) {a[x].sum=a[ls(x)].sum^a[rs(x)].sum^a[x].val;}
 28 IL int nroot(int x) //返回1说明x不是根,返回0说明x是根 
 29 {return ls(fa(x))==x||rs(fa(x))==x;}
 30 
 31 IL void pushdown(int x) {
 32     if(a[x].rev) {
 33         a[x].rev=0;
 34         if(ls(x)) Rev(ls(x));
 35         if(rs(x)) Rev(rs(x));
 36     }
 37 }
 38 
 39 IL void pushall(int x) {
 40     if(nroot(x)) pushall(fa(x));
 41     pushdown(x);    
 42 }
 43 
 44 IL void rotate(int x) {
 45     int y=fa(x),z=fa(y),k=chk(x),w=a[x].ch[k^1];
 46     if(nroot(y)) a[z].ch[chk(y)]=x;fa(x)=z;
 47     if(w) fa(w)=y;a[y].ch[k]=w;
 48     fa(y)=x;a[x].ch[k^1]=y;
 49     pushup(y);pushup(x);
 50 }
 51 
 52 IL void splay(int x) {//把x转到splay的根 
 53     pushall(x);
 54     while(nroot(x)) {
 55         int y=fa(x);
 56         if(nroot(y)) rotate(chk(x)^chk(y)?x:y);
 57         rotate(x);
 58     }
 59 }
 60 
 61 IL void access(int x) {//打通从根节点到x的路径,x最深
 62     for(R y=0; x; x=fa(y=x)) {
 63         splay(x),rs(x)=y,pushup(x);
 64     }
 65 }
 66 
 67 IL void makeroot(int x) {//把x变为原树的根
 68     access(x),splay(x),Rev(x);
 69 }
 70 
 71 IL int findroot(int x) {//找到x的原树的根
 72     access(x),splay(x);
 73     while(ls(x)) pushdown(x),x=ls(x);
 74     return x;
 75 }
 76 
 77 IL void split(int x,int y) {//y维护x-y路径上的信息
 78     makeroot(x),access(y),splay(y);
 79 }
 80 
 81 IL void link(int x,int y) {
 82     makeroot(x);if(findroot(y)!=x)  fa(x)=y;
 83 }
 84 
 85 IL void cut(int x,int y) {
 86     split(x,y);
 87     if(fa(x)==y&&rs(x)==0) fa(x)=ls(y)=0,pushup(y);
 88 }
 89 
 90 int main() {
 91     n=read();
 92     m=read();
 93     for(R i=1; i<=n; ++i) a[i].val=a[i].sum=read();
 94     while(m--) {
 95         int op=read(),x=read(),y=read();
 96         if(!op) split(x,y),printf("%d\n",a[y].sum);
 97         else if(op==1) link(x,y);
 98         else if(op==2) cut(x,y);
 99         else makeroot(x),a[x].val=y,pushup(x);
100     }
101     return 0;
102 }
展开这里看完整代码

 

posted @ 2021-03-12 20:42  endl\n  阅读(225)  评论(0编辑  收藏  举报