Link Cut Tree 应用二

两篇博客介绍了如何利用Splay Tree解决在线问题,涉及LCT(Link-Cut Tree)操作,包括链接、剪切、查找根节点等,时间复杂度为O(mlogn),常数较大。题目分别为SDOI2008洞穴勘测和部落冲突,代码实现详细,适合理解Splay Tree模板。
摘要由CSDN通过智能技术生成

2022年02月04日,第十六天

1. 题目链接:P2147 [SDOI2008] 洞穴勘测

思路 L C T LCT LCT 在线解决,时间复杂度 O ( m l o g   n ) O(mlog\ n) O(mlog n) ,常数巨大。模板题,不必多言。

#include <bits/stdc++.h>
#define ull unsigned long long
#define ll long long
#define re register
#define endl '\n'

using namespace std;

const int MOD = 998244353;
const int inf = 0x3f3f3f3f;
const double eps = 1e-8;
const double Pi = acos(-1.0);
const int N = 1e5 + 5;

#define ls(x) (ch[x][0])
#define rs(x) (ch[x][1])

int ch[N][2], fa[N];
int siz[N], rev[N];
int n, m, st[N], top;

inline int ident (int x, int f) { return rs(f) == x; }
inline bool isroot (int x) { 
    return ls(fa[x]) != x && rs(fa[x]) != x;
}
inline void pushup (int x) {
    siz[x] = siz[ls(x)] + siz[rs(x)] + 1;
}
inline void pushrev (int x) {
    swap (ls(x), rs(x));
    rev[x] ^= 1;
}
inline void pushdown (int x) {
    if (rev[x]) {
        if (ls(x)) pushrev (ls(x));
        if (rs(x)) pushrev (rs(x));
        rev[x] = 0;
    }
}
inline void rotate (int x) {
    int y = fa[x], z = fa[y], k = ident (x, y);
    if (! isroot (y)) ch[z][ident (y, z)] = x;
    ch[y][k] = ch[x][k ^ 1], ch[x][k ^ 1] = y;
    if (ch[y][k]) fa[ch[y][k]] = y;
    fa[x] = z, fa[y] = x;
    pushup (y), pushup (x);
}
inline void splay (int x) {
    int r = x;
    st[top = 1] = r;
    while (! isroot (r)) st[++ top] = r = fa[r];
    while (top) pushdown (st[top --]);
    while (! isroot (x)) {
        int y = fa[x], z = fa[y];
        if (! isroot (y)) 
            rotate (ident (x, y) ^ ident (y, z) ? x : y);
        rotate (x);
    }
    pushup (x);
}
inline void access (int x) {
    for (int y = 0; x; x = fa[y = x]) 
        splay (x), rs(x) = y, pushup (x);
}
inline void makeroot (int x) {
    access (x);
    splay (x);
    pushrev (x);
}
inline int findroot (int x) {
    access (x), splay (x);
    while (ls(x)) pushdown (x), x = ls(x);
    splay (x);
    return x;
}
inline void split (int x, int y) {
    makeroot (x);
    access (y);
    splay (y);
}
inline void link (int x, int y) {
    makeroot (x);
    if (findroot (y) != x) 
        fa[x] = y;
}
inline void cut (int x, int y) {
    makeroot (x);
    if (findroot (y) == x && fa[y] == x && ! ls(y)) 
        fa[y] = rs(x) = 0, pushup (x);
}

int main() {
    ios::sync_with_stdio(false), cin.tie(0), cout.tie(0); 
    cin >> n >> m;
    while (m --) {
        char op[20];
        int u, v;
        cin >> op >> u >> v;
        if (* op == 'C') link (u, v);
        if (* op == 'D') cut (u, v);
        if (* op == 'Q') 
            if (findroot (u) == findroot (v)) cout << "Yes" << endl;
            else cout << "No" << endl;
        }
    }
    return 0;
}

2. 题目链接:P3950 部落冲突

思路 L C T LCT LCT 在线解决,时间复杂度 O ( m l o g   n ) O(mlog\ n) O(mlog n) ,常数巨大。模板题,不必多言。

#include <bits/stdc++.h>
#define ull unsigned long long
#define ll long long
#define re register
#define endl '\n'

using namespace std;

const int MOD = 998244353;
const int inf = 0x3f3f3f3f;
const double eps = 1e-8;
const double Pi = acos(-1.0);
const int N = 3e5 + 5;

#define ls(x) (ch[x][0])
#define rs(x) (ch[x][1])

int ch[N][2], fa[N];
int siz[N], rev[N];
int n, m, st[N], top;
int a[N], b[N], cnt;

inline int ident (int x, int f) { return rs(f) == x; }
inline bool isroot (int x) { 
    return ls(fa[x]) != x && rs(fa[x]) != x;
}
inline void pushup (int x) {
    siz[x] = siz[ls(x)] + siz[rs(x)] + 1;
}
inline void pushrev (int x) {
    swap (ls(x), rs(x));
    rev[x] ^= 1;
}
inline void pushdown (int x) {
    if (rev[x]) {
        if (ls(x)) pushrev (ls(x));
        if (rs(x)) pushrev (rs(x));
        rev[x] = 0;
    }
}
inline void rotate (int x) {
    int y = fa[x], z = fa[y], k = ident (x, y);
    if (! isroot (y)) ch[z][ident (y, z)] = x;
    ch[y][k] = ch[x][k ^ 1], ch[x][k ^ 1] = y;
    if (ch[y][k]) fa[ch[y][k]] = y;
    fa[x] = z, fa[y] = x;
    pushup (y), pushup (x);
}
inline void splay (int x) {
    int r = x;
    st[top = 1] = r;
    while (! isroot (r)) st[++ top] = r = fa[r];
    while (top) pushdown (st[top --]);
    while (! isroot (x)) {
        int y = fa[x], z = fa[y];
        if (! isroot (y)) 
            rotate (ident (x, y) ^ ident (y, z) ? x : y);
        rotate (x);
    }
    pushup (x);
}
inline void access (int x) {
    for (int y = 0; x; x = fa[y = x]) 
        splay (x), rs(x) = y, pushup (x);
}
inline void makeroot (int x) {
    access (x);
    splay (x);
    pushrev (x);
}
inline int findroot (int x) {
    access (x), splay (x);
    while (ls(x)) pushdown (x), x = ls(x);
    splay (x);
    return x;
}
inline void split (int x, int y) {
    makeroot (x);
    access (y);
    splay (y);
}
inline void link (int x, int y) {
    makeroot (x);
    if (findroot (y) != x) 
        fa[x] = y;
}
inline void cut (int x, int y) {
    makeroot (x);
    if (findroot (y) == x && fa[y] == x && ! ls(y)) 
        fa[y] = rs(x) = 0, pushup (x);
}

int main() {
    ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
    cin >> n >> m;
    for (int i = 1; i < n; i ++) {
        int u, v; cin >> u >> v;
        link (u, v);
    }
    while (m --) {
        char op[2]; int u, v;
        cin >> op;
        if (* op == 'U') {
            cin >> u;
            link (a[u], b[u]);
        }
        if (* op == 'C') {
            cin >> u >> v;
            a[++ cnt] = u, b[cnt] = v;
            cut (u, v);
        }
        if (* op == 'Q') {
            cin >> u >> v;
            if (findroot (u) == findroot (v)) cout << "Yes" << endl;
            else cout << "No" << endl;
        }
    }
    return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值