LCT (模板)

版权声明:本文为博主原创文章,喜欢就点个赞吧 https://blog.csdn.net/Anxdada/article/details/81777558

模板题 - P3369
其中这道题的题解的第一篇讲解LCT异常详细, 可以通过这个来学习LCT, 另外再附上三篇详细博客, 基本上是讲解的最清楚的乐.
第一篇
第二篇
第三篇(最好的一篇)

模板题AC Code

const int maxn = 3e5 + 5;
int a[maxn];
struct node {
    int fa, son[2], sz, val, lazy;
    void init() {
        sz = 1; lazy = 0;
        fa = son[0] = son[1] = 0;
    }
}t[maxn];
bool nroot(int x) {
    return t[t[x].fa].son[0] == x || t[t[x].fa].son[1] == x;
}
void update(int x) {
    t[x].val = a[x];
    int l = t[x].son[0], r = t[x].son[1];
    if(l) t[x].val ^= t[l].val;
    if(r) t[x].val ^= t[r].val;
}
void pushdown(int x) {
    if(t[x].lazy) {
        t[x].lazy = 0;
        swap(t[x].son[0], t[x].son[1]);
        t[t[x].son[0]].lazy ^= 1;
        t[t[x].son[1]].lazy ^= 1;
    }
}
void rot(int x) {
    int fa = t[x].fa, gfa = t[t[x].fa].fa;
    int k = (x == t[fa].son[1]);
    t[fa].son[k] = t[x].son[k^1];
    if(nroot(fa)) t[gfa].son[fa == t[gfa].son[1]] = x;
    if(t[x].son[k^1]) t[t[x].son[k^1]].fa = fa;
    t[x].son[k^1] = fa;
    t[fa].fa = x; t[x].fa = gfa;
    update(fa);
}
int stk[maxn], top;
void splay(int x) {
    top = 0; stk[++top] = x;
    for(int i = x ; nroot(i) ; i = t[i].fa) {
        stk[++top] = t[i].fa;
    }
    while(top) pushdown(stk[top--]);
    for(int fa ; nroot(x) ; rot(x)) {
        if(nroot(fa = t[x].fa))
            rot((t[x].son[0] == x) ^ (t[fa].son[0] == fa) ? fa : x);
    }
    update(x);
}
int access(int x) {
    int i;
    for(i = 0 ; x ; x = t[i = x].fa) {
        splay(x); t[x].son[1] = i; update(x);
    }
    return i;
}
int lca(int x, int y) {
    access(x); return access(y);
}
void makeroot(int x){
    access(x); splay(x); t[x].lazy ^= 1;
}
int findroot(int x) {
    access(x); splay(x);
    while(t[x].son[0]) pushdown(x), x = t[x].son[0];
    return x;
}
void split(int x, int y) {
    makeroot(x); access(y); splay(y);
}
void link(int x, int y) {
    makeroot(x);
    if(findroot(y) != x) t[x].fa = y;
}
void cut(int x, int y) {
    makeroot(x);
    if(findroot(y) == x && t[x].fa == y && !t[x].son[1]){
        t[x].fa = t[y].son[0] = 0;
        update(y);
    }
}
int query(int x, int y) {
    split(x, y);
    return t[y].val;
}
void solve() {
    int n, m;
    scanf("%d%d", &n, &m);
    for (int i = 1 ; i <= n ; i ++) {
        scanf("%d", a+i);
        t[i].init(); t[i].val = a[i];
    }
    while(m--) {
        int op, x, y;
        scanf("%d%d%d", &op, &x, &y);
        if (!op) printf("%d\n", query(x, y));
        else if (op == 1) link(x, y);
        else if (op == 2) cut(x, y);
        else splay(x), a[x] = y;
    }
}

这个由于太难了, 时间久了怕忘记一些东西的作用, 所以再附上解释版.

const int maxn = 300009;
int a[maxn];
struct node {
    int fa, son[2], sz, val, lazy;
    void init() {
        sz = 1; lazy = 0;
        fa = son[0] = son[1] = 0;
    }
}t[maxn];
bool nroot(int x) { //判断节点是否为一个Splay的根(与普通Splay的区别1)
    return t[t[x].fa].son[0] == x || t[t[x].fa].son[1] == x;
} //原理很简单,如果连的是轻边,他的父亲的儿子里没有它
void update(int x) {  //更新信息
    t[x].val = a[x];
    int l = t[x].son[0], r = t[x].son[1];
    if(l) t[x].val ^= t[l].val;
    if(r) t[x].val ^= t[r].val;
}
void pushr(int x){
    swap(t[x].son[0], t[x].son[1]);
    r[x] ^= 1;
} //翻转操作(这里没有用到)
void pushdown(int x) { //判断并释放懒标记
    if(t[x].lazy) {
        t[x].lazy = 0;
        swap(t[x].son[0], t[x].son[1]);
        t[t[x].son[0]].lazy ^= 1;
        t[t[x].son[1]].lazy ^= 1;
    }
}
void rot(int x) {  //一次旋转(左右旋都可进行)
    int fa = t[x].fa, gfa = t[t[x].fa].fa;
    int k = (x == t[fa].son[1]);
    t[fa].son[k] = t[x].son[k^1];
    if(nroot(fa)) t[gfa].son[fa == t[gfa].son[1]] = x;
    //额外注意if(nroot(y))语句, 此处不判断会引起致命错误(普通Splay的区别2)
    if(t[x].son[k^1]) t[t[x].son[k^1]].fa = fa;
    t[x].son[k^1] = fa;
    t[fa].fa = x; t[x].fa = gfa;
    update(fa);
}
int stk[maxn], top;
void splay(int x) { //只传了一个参数,因为所有操作的目标都是该Splay的根(与普通Splay的区别3)
    top = 0; stk[++top] = x;
    for(int i = x ; nroot(i) ; i = t[i].fa) {
        stk[++top] = t[i].fa;
    }
    while(top) pushdown(stk[top--]); // 一路释放懒人标记
    //st为栈,暂存当前点到根的整条路径,pushdown时一定要从上往下放标记(与普通Splay的区别4)
    for(int fa ; nroot(x) ; rot(x)) {
        if(nroot(fa = t[x].fa))
            rot((t[x].son[0] == x) ^ (t[fa].son[0] == fa) ? fa : x);
    }
    update(x);
}
int access(int x) { // 访问
    int i;
    for(i = 0 ; x ; x = t[i = x].fa) {
        splay(x); t[x].son[1] = i; update(x);
    }
    return i; // 返回最后一次修改右孩子的点.
}
int lca(int x, int y) {
    access(x); return access(y);
}
void makeroot(int x) { //换根
    access(x); splay(x); t[x].lazy ^= 1;
}
int findroot(int x) {  //找根(在真实的树中的)
    access(x); splay(x);
    while(t[x].son[0]) pushdown(x), x = t[x].son[0];
    return x;
}
void split(int x, int y) {  //提取路径(以y作为根)
    makeroot(x); access(y); splay(y);
}
void link(int x, int y) { //连边
    makeroot(x);
    if(findroot(y) != x) t[x].fa = y;
}
void cut(int x, int y) { //断边
    makeroot(x);
    if(findroot(y) == x && t[x].fa == y && !t[x].son[1]){
        t[x].fa = t[y].son[0] = 0;
        update(y);
    }
}
int query(int x, int y) {
    split(x, y);
    return t[y].val;
}
void solve() {
    int n, m;
    scanf("%d%d", &n, &m);
    for (int i = 1 ; i <= n ; i ++) {
        scanf("%d", a+i);
        t[i].init(); t[i].val = a[i];
    }
    while(m--){
        int op, x, y;
        scanf("%d%d%d", &op, &x, &y);
        if (!op) printf("%d\n", query(x, y));
        else if (op == 1) link(x, y);
        else if (op == 2) cut(x, y);
        else splay(x), a[x] = y;
    }
}

猜你喜欢

转载自blog.csdn.net/Anxdada/article/details/81777558
LCT