洛谷 P3391 【模板】文艺平衡树(Splay)

本文介绍了一道洛谷平台上的编程题目,并通过使用类似线段树的维护标记的方法来解决这个问题。该解决方案利用了Treap(即随机化平衡二叉搜索树)的数据结构,详细展示了插入元素、查找第k个元素等操作的具体实现。

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

作者:岸芷汀兰

一、题目

洛谷原题

二、思路

类似线段树的维护标记。

三、代码

#include<iostream>
#include<cstdio>

using namespace std;
inline int read(void) {
    int x = 0, f = 1; char ch = getchar();
    while (ch<'0' || ch>'9') {
        if (ch == '-')f = -1;
        ch = getchar();
    }
    while (ch >= '0'&&ch <= '9') {
        x = x * 10 + ch - '0';
        ch = getchar();
    }
    return f * x;
}

const int maxn = 100005;

int n, m, key[maxn], ch[maxn][2], rev[maxn], f[maxn], siz[maxn], sz, root;

inline bool get(int x) {
    return ch[f[x]][1] == x;
}

inline void clear(int x) {
    key[x] = siz[x] = rev[x] = ch[x][0] = ch[x][1] = f[x] = 0;
}

inline void pushup(int x) {
    siz[x] = siz[ch[x][0]] + siz[ch[x][1]] + 1;
}

inline void rotate(int x) {
    int y = f[x], z = f[y], w = get(x), w2 = get(y);
    ch[y][w] = ch[x][w ^ 1]; f[ch[y][w]] = y;
    ch[x][w ^ 1] = y; f[y] = x;
    f[x] = z; if (z)ch[z][w2] = x;
    pushup(y); pushup(x);
}

inline void splay(int x, int goal) {
    for (register int fa = 0; (fa = f[x]) != goal; rotate(x)) {
        if (f[fa] != goal) {
            get(x) == get(fa) ? rotate(fa) : rotate(x);
        }
    }
    if (!goal)root = x;
}

inline void pushdown(int x) {
    if (rev[x]) {
        if (ch[x][0])rev[ch[x][0]] ^= 1;
        if (ch[x][1])rev[ch[x][1]] ^= 1;
        swap(ch[x][0], ch[x][1]); rev[x] = 0;
    }
}

inline void insert(int x) {
    if (!root) { key[++sz] = x; siz[x] = 1; root = sz; return; }
    int now = root, fa = 0;
    while (true) {
        pushdown(now);
        fa = now;
        now = ch[now][x > key[now]];
        if (!now) {
            ch[fa][x > key[fa]] = ++sz;
            key[sz] = x; siz[sz] = 1; f[sz] = fa;
            splay(sz, 0); return;
        }
    }
}

inline int kth(int k) {
    int now = root;
    while (true) {
        pushdown(now);
        if (ch[now][0] && k <= siz[ch[now][0]])now = ch[now][0];
        else {
            if (k <= siz[ch[now][0]] + 1) { splay(now, 0); return now; }
            k -= siz[ch[now][0]] + 1; now = ch[now][1];
        }
    }
}

inline void print(int x) {
    pushdown(x);
    if (ch[x][0])print(ch[x][0]);
    if (key[x] > 1 && key[x] < n + 2)printf("%d ", key[x] - 1);
    if (ch[x][1])print(ch[x][1]);
}

int main()
{
    n = read(); m = read();
    for (register int i = 1; i <= n + 2; i++)insert(i);
    while (m--) {
        int l = read(), r = read();
        l = kth(l); r = kth(r + 2); splay(l, 0); splay(r, l);
        rev[ch[r][0]] ^= 1;
    }
    kth(2);
    print(root);
    return 0;
}

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值