LCT学习笔记

来源:互联网 发布:mac用户文件夹在哪里 编辑:程序博客网 时间:2024/06/04 19:28

LCT是一种比较神的数据结构,它能够支持对树的link,cut,换根和各种维护边权点权,链的信息的比较神的数据结构。其主要思想是利用splay维护每一条偏爱链,利用access操作,动态的变幻树的结构,以达到查询目的。

splay以深度为关键字。

splay要求支持:

int fa[N] , ch[N][2] , S[N] , a[N];bool rev[N];void pushup(int x) {    S[x] = S[ch[x][0]] + S[ch[x][1]] + 1;}void pushdown(int x) {    if(rev[x]) {        rev[ch[x][0]] ^= 1;        rev[ch[x][1]] ^= 1;        swap(ch[x][0],ch[x][1]);        rev[x] = 0;    }}int dir(int x) {    return (x == ch[fa[x]][1]);}bool isroot(int x) {    return ((ch[fa[x]][0] != x) && (ch[fa[x]][1] != x));}void rotate(int x) {    int F = fa[x] , GF = fa[F];    int dir_x = dir(x);    if(!isroot(F)) ch[GF][dir(F)] = x;    fa[x] = GF; fa[F] = x;    ch[F][dir_x] = ch[x][!dir_x];    if(ch[x][!dir_x])fa[ch[x][!dir_x]] = F;    ch[x][!dir_x] = F;    pushup(F);pushup(x);}void splay(int x) {    stack<int>F;    while(!F.empty()) F.pop();    F.push(x);    //* * * warning* * *//    for(int i = x;!isroot(i);i = fa[i]) F.push(fa[i]);    while(!F.empty()) {        int V = F.top(); F.pop();        pushdown(V);    }    while(!isroot(x) && !isroot(fa[x])) {        if(dir(fa[x]) == dir(x)) {            rotate(fa[x]); rotate(x);        }        else rotate(x) , rotate(x);    }    if(!isroot(x)) rotate(x);}

access(x)操作,可以把x到x这个联通块的根在splay上连接起来:
具体是从x一直往上跳先,把他旋到原联通块splay的根,把原来的右儿子赋给x到根路径上的下一个点,如果是x,那么就应该断开他的右儿子。
因为是splay,所以不用管左儿子(仔细思考)。

void access(int x) {    int t = 0;    while(x) {        splay(x);        ch[x][1] = t;        pushup(x);        t = x;        x = fa[x];    }}

make_root操作,先access(x),之后把x,旋到根,将这条链上的所有点的splay树上的左右儿子交换——即深度倒序。
直观地理解一下:
x的儿子对于x的深度大小关系不变,链上其它点的子树对于其父亲深度关系不变,只有链上的点深度倒了一下,就打个交换标记即可。

void make_root(int x) {    access(x); splay(x); rev[x] ^= 1;}

link(x,y)直接x变根然后把y赋成他的父亲。

void link(int x,int y) {    make_root(x); fa[x] = y;}

cut 很直观。

void cut(int x ,int y) {    make_root(x);access(y);    splay(y);    ch[y][0] = fa[x] = 0 ,pushup(y);}

查询连通性:找联通快的根比较是否相同:

int find(int x) {    access(x);    splay(x);    while(ch[x][0]) x = ch[x][0];    return x;}

例题1:
BZOJ2049cave

裸题判连通性。

#include<bits/stdc++.h>using namespace std;const int N = 10005;char ty[11];int n , m  , x , y , fa[N] , ch[N][2];bool rev[N];inline bool isroot(int x) {    return ((ch[fa[x]][0] != x) && (ch[fa[x]][1] != x));}inline int dir(int x) {    return (ch[fa[x]][1] == x);}inline void pushdown(int x) {    if(rev[x]) {        rev[x] = 0;        swap(ch[x][0] , ch[x][1]);        rev[ch[x][0]] ^= 1;        rev[ch[x][1]] ^= 1;    }}inline void rotate(int x) {    int F = fa[x] , dir_x = dir(x), GF = fa[F];    if(!isroot(F)) {        ch[GF][dir(F)] = x;    }    fa[F] = x; fa[x] = GF;    ch[F][dir_x] = ch[x][!dir_x];    if(ch[F][dir_x]) fa[ch[F][dir_x]] = F;    ch[x][!dir_x] = F;}int st[N];inline void splay(int x) {    int top = 0;    st[++top] = x;    for(int i = x;!isroot(i);i = fa[i]) {        st[++ top] = fa[i];    }    while(1) {        pushdown(st[top]);        top --;        if(top ==0) break;    }    while(!isroot(x) && !isroot(fa[x])) {        if(dir(x) == dir(fa[x])) {            rotate(fa[x]);rotate(x);        }        else rotate(x) , rotate(x);    }    if(!isroot(x)) rotate(x);}int t;inline void access(int x) {    t = 0;    while(x) {        splay(x);        ch[x][1] = t;        t = x;        x = fa[x];    }}inline void make_root(int x) {    access(x); splay(x); rev[x] ^= 1;} inline void link(int x,int y) {    make_root(x); fa[x] = y;}inline void cut(int x ,int y) {    make_root(x);    access(y);    splay(y);    fa[x] = ch[y][0] = 0;}int Find(int x) {    access(x);    splay(x);    while(ch[x][0]) x = ch[x][0];    // 人工找联通快的最高点     return x;}int main() {    scanf("%d%d",&n,&m);    for(int i = 1;i <= m;i ++) {        scanf("%s",ty);        scanf("%d%d",&x,&y);        if(ty[0] == 'Q') {            if(Find(x) == Find(y)) {                puts("Yes");            }            else puts("No");        }        if(ty[0] == 'C') link(x,y);        if(ty[0] == 'D') cut(x,y);    }}

BZOJ 2002 弹飞绵羊,查询深度。

%:pragma GCC optimize(2)#include<bits/stdc++.h>using namespace std;const int N = 200005;int n;int fa[N] , ch[N][2] , S[N] , a[N];bool rev[N];void pushup(int x) {    S[x] = S[ch[x][0]] + S[ch[x][1]] + 1;}void pushdown(int x) {    if(rev[x]) {        rev[ch[x][0]] ^= 1;        rev[ch[x][1]] ^= 1;        swap(ch[x][0],ch[x][1]);        rev[x] = 0;    }}int dir(int x) {    return (x == ch[fa[x]][1]);}bool isroot(int x) {    return ((ch[fa[x]][0] != x) && (ch[fa[x]][1] != x));}void rotate(int x) {    int F = fa[x] , GF = fa[F];    int dir_x = dir(x);    if(!isroot(F)) ch[GF][dir(F)] = x;    fa[x] = GF; fa[F] = x;    ch[F][dir_x] = ch[x][!dir_x];    if(ch[x][!dir_x])fa[ch[x][!dir_x]] = F;    ch[x][!dir_x] = F;    pushup(F);pushup(x);}void splay(int x) {    stack<int>F;    while(!F.empty()) F.pop();    F.push(x);    //* * * warning* * *//    for(int i = x;!isroot(i);i = fa[i]) F.push(fa[i]);    while(!F.empty()) {        int V = F.top(); F.pop();        pushdown(V);    }    while(!isroot(x) && !isroot(fa[x])) {        if(dir(fa[x]) == dir(x)) {            rotate(fa[x]); rotate(x);        }        else rotate(x) , rotate(x);    }    if(!isroot(x)) rotate(x);}//简略写法。 void access(int x) {    int t = 0;    while(x) {        splay(x);        ch[x][1] = t;        pushup(x);        t = x;        x = fa[x];    }}void make_root(int x) {    access(x); splay(x); rev[x] ^= 1;}void link(int x,int y) {    make_root(x); fa[x] = y;}void cut(int x ,int y) {    make_root(x);access(y);    splay(y);    ch[y][0] = fa[x] = 0 ,pushup(y);}int find(int x) {    access(x);    splay(x);    while(ch[x][0]) x = ch[x][0];    return x;}int main() {    scanf("%d",&n);    int ty , x , y;    for(int i = 1;i <= n;i ++) {        scanf("%d",&a[i]);        link(i,min(i+a[i],n+1));    }    int q;scanf("%d",&q);    for(int i = 1;i <= q;i ++) {        scanf("%d%d",&ty,&x);        x ++;        if(ty == 1) {            make_root(n + 1);            access(x);splay(x);            printf("%d\n",S[x] - 1);        }        else {            scanf("%d",&y);            cut(x,min(n + 1, x+ a[x]));            link(x,min(n + 1, x+ y));            a[x] = y;        }    }}
原创粉丝点击