洛谷P3835 可持续化平衡树题解(非旋Treap)

题目链接

题意

您需要写一种数据结构(可参考题目标题),来维护一个可重整数集合,其中需要提供以下操作,(对于各个以往的历史版本):
case 1: 插入 x x x
case 2: 删除 x x x数(若有多个相同的数,因只删除一个)
case 3: 查询 x x x数的排名(排名定义为比当前数小的数的个数 + 1 +1 +1)
case 4: 查询排名为 x x x的数
case 5: x x x的前驱(前驱定义为小于 x x x,且最大的数,如不存在输出 − 2 31 + 1 -2^{31}+1 231+1)
case 6: x x x的后继(后继定义为大于 x x x,且最小的数,不存在输出 2 31 − 1 2^{31}-1 2311)
和原本平衡树不同的一点是,每一次的任何操作都是基于某一个历史版本,同时生成一个新的版本。(操作3, 4, 5, 6即保持原版本无变化)
每个版本的编号即为操作的序号(版本0即为初始状态,空树)

思路


笔者是用这个思路过了的
在这里我们需要用到多个根
和可持续化线段树一样
每一次操作我们建一段新树
然后把根保存起来

注意事项

数组大小开50
笔者亲测50倍能过, RE了好几次

(求互关)
根单独存放
第一次操作的根是0

代码

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cstdlib>
#include <cctype>
#include <map>
#include <set>
#include <vector>
#include <iostream>
#include <cmath>
#define pk putchar(' ')
#define ph puts("")
#pragma GCC optimize(2)
using namespace std;
typedef long long ll;
template <class T>
void rd(T &x)
{
    x = 0;
    int f = 1;
    char c = getchar();
    while (!isdigit(c)) {if (c == '-') f = -1; c = getchar();}
    while (isdigit(c)) x = (x << 3) + (x << 1) + (c ^ 48), c = getchar();
    x *= f;
}
template <class T>
void pt(T x)
{
    if (x < 0)
        putchar('-'), x = (~x) + 1;
    if (x > 9)
        pt(x / 10);
    putchar(x % 10 ^ 48);
}
template <class T>
T Max(T a, T b)
{
    return a > b ? a : b;
}
template <class T>
T Min(T a, T b)
{
    return a < b ? a : b;
}
using namespace std;
const int INF = 0x3f3f3f3f, N = 5e5 + 5;
int n, rt[N];
struct Node 
{
    int val, rnd, siz, l ,r;
};
struct Treapnode
{
    Node t[N * 50];
    int tot;
    void New(int &p, int x)
    {
        p = ++tot;
        t[p].val = x;
        t[p].siz = 1;
        t[p].rnd = rand();
    }
    void update(int p)
    {
        t[p].siz = t[t[p].l].siz + t[t[p].r].siz + 1;
    }
    // 更新
    int merge(int a,int b)
    {
        if (!a || !b)
            return a + b;
        if (t[a].rnd > t[b].rnd)
        {
            int p = ++tot;
            t[p] = t[a];
            t[p].r = merge(t[p].r, b);
            update(p);
            return p;
        }
        else
        {
            int p = ++tot;
            t[p] = t[b];
            t[p].l = merge(a, t[p].l);
            update(p);
            return p;
        }
    }
    // 合并
    void split(int p, int k, int& x, int& y) 
    {
        if (!p) 
            return (void)(x = y = 0); 
        if (t[p].val <= k) 
        {
            x = ++tot;
            t[x] = t[p];
            split(t[x].r, k, t[x].r, y);
            update(x);
        }
        else 
        {
            y = ++tot;
            t[y] = t[p];
            split(t[y].l, k, x, t[y].l);
            update(y);
        }
    }
    // 按权值大小拆分
    void ins(int& p, int x) 
    {
        int a = 0, b = 0, c = 0;
        split(p, x, a, b);
        New(c, x);
        p = merge(merge(a, c), b);
    }
    // 插入x
    void del(int& p, int x) 
    {
        int a = 0, b = 0, c = 0;
        split(p, x, a, c);
        split(a, x - 1, a, b);
        b = merge(t[b].l, t[b].r);
        p = merge(merge(a, b), c);
    }
    // 删除x
    int get_rank(int& p, int x) 
    {
        int a, b, c;
        split(p, x - 1, a, b);
        c = t[a].siz + 1;
        p = merge(a, b);
        return c;
    }
    int get_val(int p, int x)
    {
        if (x == t[t[p].l].siz + 1)
            return t[p].val;
        else if (x <= t[t[p].l].siz)
            return get_val(t[p].l, x);
        else 
            return get_val(t[p].r, x - t[t[p].l].siz - 1);
    }
    // 找第x的值
    int pre(int& p, int x) 
    {
        int a, b, c;
        split(p, x - 1, a, b);
        if (!a)
            return -2147483647;
        c = get_val(a, t[a].siz);
        p = merge(a, b);
        return c;
    }
    // 找前驱
    int sub(int& p, int x) 
    {
        int a, b, c;
        split(p, x, a, b);
        if (!b)
            return 2147483647;
        c = get_val(b, 1);
        p = merge(a, b);
        return c;
    }
    // 找后缀
}Treap;
int main() 
{
    // freopen("testdata.in", "r", stdin);
    // freopen("test.out", "w", stdout);
    rd(n);
    int tim, opt, x;
    for (int i = 1;i <= n; i++)
    {
        rd(tim), rd(opt), rd(x);
        rt[i] = rt[tim];
        switch(opt)
        {
            case 1: Treap.ins(rt[i], x); break;
            case 2: Treap.del(rt[i], x); break;
            case 3: pt(Treap.get_rank(rt[i], x)), ph; break;
            case 4: pt(Treap.get_val(rt[i], x)), ph; break;
            case 5: pt(Treap.pre(rt[i], x)), ph; break;
            case 6: pt(Treap.sub(rt[i], x)), ph; break;
        }
    }
    return 0;
}

Thanks!

评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值