BZOJ2049 洞穴勘测 LCT

本文介绍了一种基于链式分治树的数据结构实现方法,该方法通过一系列操作如查询、连接和切割来维护节点之间的关系。具体实现涉及到了自底向上地构建树形结构、旋转操作以达到平衡以及懒惰标记的更新等关键步骤。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <iostream>
#include <algorithm>
#include <set>
#include <map>
#include <stack>
#include <queue>
#include <vector>

using namespace std;

#define REP(i, a, b) for (int i = (a), _end_ = (b); i <= _end_; ++i)
#define DREP(i, a, b) for (int i = (a), _begin_ = (b); i >= _begin_; --i)
#define debug(...) fprintf(stderr, __VA_ARGS__)
#define mp make_pair
#define x first
#define y second
#define pb push_back
#define SZ(x) (int((x).size()))
#define ALL(x) (x).begin(), (x).end()

template<typename T> inline bool chkmin(T &a, const T &b){ return a > b ? a = b, 1 : 0; }
template<typename T> inline bool chkmax(T &a, const T &b){ return a < b ? a = b, 1 : 0; }

typedef long long LL;

const int dmax = 300100, oo = 0x3f3f3f3f;

int N, M;

struct node
{
    node *f, *ch[2];
    int size, rev;
}c[dmax], *cur, *Null;

#define L ch[0]
#define R ch[1]

inline node *new_node()
{
    cur->size = 1;
    cur->rev = 0;
    cur->f = cur->L = cur->R = Null;
    return cur++;
}

inline void init()
{
    cur = c + 1;
    Null = c;
    Null->f = Null->L = Null->R = Null;
    Null->size = Null->rev = 0;
}

struct lct
{
    inline bool is_root(node *t){ return t == Null || t->f->L != t && t->f->R != t; }
    inline void push_up(node *t){ t->size = t->L->size + t->R->size + 1; }
    inline void push_down(node *x)
    {
        if (x->rev)
        {
            if (x->L != Null) x->L->rev ^= 1;
            if (x->R != Null) x->R->rev ^= 1;
            x->rev = 0;
            swap(x->L, x->R);
        }
    }
    inline void rotate(node *x)
    {
        if (is_root(x)) return;
        node *y = x->f;
        if (!is_root(y))
        {
            if (y == y->f->L)
                y->f->L = x;
            else y->f->R = x;
        }
        x->f = y->f;
        int T = x == y->R;
        y->ch[T] = x->ch[!T];
        if (x->ch[!T] != Null) x->ch[!T]->f = y;
        x->ch[!T] = y;
        y->f = x;
        push_up(x);
    }
    void splay(node *x)
    {
        static node *S[dmax];
        S[0] = x;
        int top = 1;
        for (node *y = x; !is_root(y); y = y->f)
            S[top++] = y->f;
        while (top) push_down(S[--top]);
        while (!is_root(x))
        {
            node *y = x->f;
            if (is_root(y))
                rotate(x);
            else{
                if (x == y->f->L->L || x == y->f->R->R)
                    rotate(y);
                else rotate(x);
                rotate(x);
            }
        }
    }
    node *access(node *x)
    {
        node *y = Null;
        while (x != Null)
        {
            splay(x);
            x->R = y;
            y->f = x;
            push_up(x);
            y = x;
            x = x->f;
        }
        return y;
    }
    inline void change_root(node *x)
    {
        access(x);
        splay(x);
        x->rev ^= 1;
    }
    inline void link(node *x, node *y)
    {
        change_root(x);
        x->f = y;
        access(x);
    }
    inline void cut(node *x)
    {
        access(x);
        splay(x);
        x->L = x->L->f = Null;
        push_up(x);
    }
    node *get_root(node *x)
    {
        access(x);
        splay(x);
        while (x->L != Null) x = x->L;
        splay(x);
        return x;
    }
    bool p(node *x, node *y)
    {
        while (x->f != Null) x = x->f;
        while (y->f != Null) y = y->f;
        return x == y;
    }
}t;

char s[dmax];

int main()
{
#ifndef ONLINE_JUDGE
    freopen("input.txt", "r", stdin);
    freopen("output.txt", "w", stdout);
#endif
    init();
    scanf("%d%d", &N, &M);
    REP(i, 1, N)
        new_node();
    while (M--)
    {
        int x, y;
        scanf("%s%d%d", s, &x, &y);
        if (!strcmp(s, "Query"))
        {
            if (t.p(c + x, c + y))
                puts("Yes");
            else puts("No");
        } else if (!strcmp(s, "Connect"))
            t.link(c + x, c + y);
        else {
            t.change_root(c + x);
            t.cut(c + y);
        }
    }
    return 0;
}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值