[BZOJ 3224] 普通平衡树 非旋Treap

题意

  维护一个多重集合 $S$ , 支持:

    ① 插入一个数 $w$ .

    ② 删除一个数 $w$ .

    ③ 查询 $w$ 在集合中的排名.

    ④ 查询集合中排名第 $r$ 的数.

    ⑤ 求集合中 $w$ 的前驱.

    ⑥ 求集合中 $w$ 的后继.

  $N \le 100000$ .

小结

  要总结一些常见的写法和想法, 减小实现时的复杂度.

实现

#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <cctype>

#define F(i, a, b) for (register int i = (a); i <= (b); i++)

const int N = 100005;

int n;
int rt, tot, c[N][2], siz[N], fix[N], key[N];
struct D { int c[2]; };

inline int rd(void) {
    int f = 1; char c = getchar(); for (; !isdigit(c); c = getchar()) if (c == ‘-‘) f = -1;
    int x = 0; for (; isdigit(c); c = getchar()) x = x*10+c-‘0‘; return x*f;
}

inline void Pushup(int x) { siz[x] = siz[c[x][0]] + siz[c[x][1]] + 1; }
inline int Merge(int x, int y) {
    if (!x || !y) return x+y;
    if (fix[x] < fix[y]) {
        c[x][1] = Merge(c[x][1], y);
        Pushup(x);
        return x;
    }
    else {
        c[y][0] = Merge(x, c[y][0]);
        Pushup(y);
        return y;
    }
}
inline D Split(int x, int k) {
    if (!x) return D();
    if (key[x] > k) {
        D t = Split(c[x][0], k);
        c[x][0] = t.c[1], Pushup(x);
        t.c[1] = x;
        return t;
    }
    else {
        D t = Split(c[x][1], k);
        c[x][1] = t.c[0], Pushup(x);
        t.c[0] = x;
        return t;
    }
}
inline D Split_r(int x, int k) {
    if (!x) return D();
    if (siz[c[x][0]] + 1 > k) {
        D t = Split_r(c[x][0], k);
        c[x][0] = t.c[1], Pushup(x);
        t.c[1] = x;
        return t;
    }
    else {
        D t = Split_r(c[x][1], k-siz[c[x][0]]-1);
        c[x][1] = t.c[0], Pushup(x);
        t.c[0] = x;
        return t;
    }
}

inline int Newnode(int w) { return siz[++tot] = 1, fix[tot] = rand(), key[tot] = w, tot; }
inline void Insert(int w) {
    int x = Newnode(w);
    D t = Split(rt, w);
    rt = Merge(Merge(t.c[0], x), t.c[1]);
}
inline void Delete(int w) {
    //It‘s guaranteed that w exists!
    D t = Split(rt, w-1);
    D tx = Split_r(t.c[1], 1);
    rt = Merge(t.c[0], tx.c[1]);
}
inline int Get(int w) {
    D t = Split(rt, w-1);
    int res = siz[t.c[0]] + 1;
    rt = Merge(t.c[0], t.c[1]);
    return res;
}
inline int Rank(int k) {
    D t = Split_r(rt, k-1);
    D tx = Split_r(t.c[1], 1);
    int res = key[tx.c[0]];
    rt = Merge(t.c[0], Merge(tx.c[0], tx.c[1]));
    return res;
}
inline int Pre(int w) {
    D t = Split(rt, w-1);
    D tx = Split_r(t.c[0], siz[t.c[0]]-1);
    int res = key[tx.c[1]];
    rt = Merge(Merge(tx.c[0], tx.c[1]), t.c[1]);
    return res;
}
inline int Nxt(int w) {
    D t = Split(rt, w);
    D tx = Split_r(t.c[1], 1);
    int res = key[tx.c[0]];
    rt = Merge(t.c[0], Merge(tx.c[0], tx.c[1]));
    return res;
}

int main(void) {
    #ifndef ONLINE_JUDGE
        freopen("bzoj3224.in", "r", stdin);
        freopen("bzoj3224.out", "w", stdout);
    #endif

    n = rd();
    F(i, 1, n) {
        int k = rd(), x = rd();
        if (k == 1) Insert(x);
        else if (k == 2) Delete(x);
        else if (k == 3) printf("%d\n", Get(x));
        else if (k == 4) printf("%d\n", Rank(x));
        else if (k == 5) printf("%d\n", Pre(x));
        else printf("%d\n", Nxt(x));
    }

    return 0;
}
时间: 2024-10-23 22:30:51

[BZOJ 3224] 普通平衡树 非旋Treap的相关文章

[代码] bzoj 3224 普通平衡树(无旋treap)

- 传送门 - http://www.lydsy.com/JudgeOnline/problem.php?id=3224 3224: Tyvj 1728 普通平衡树 Time Limit:?10 Sec??Memory Limit:?128 MB Submit:?17311??Solved:?7553 Description 您需要写一种数据结构(可参考题目标题),来维护一些数,其中需要提供以下操作: 1. 插入x数 2. 删除x数(若有多个相同的数,因只删除一个) 3. 查询x数的排名(若有多

BZOJ 3224 普通平衡树(treap模板题)

3224: Tyvj 1728 普通平衡树 Time Limit: 10 Sec  Memory Limit: 128 MB Submit: 14301  Solved: 6208 [Submit][Status][Discuss] Description 您需要写一种数据结构(可参考题目标题),来维护一些数,其中需要提供以下操作: 1. 插入x数 2. 删除x数(若有多个相同的数,因只删除一个) 3. 查询x数的排名(若有多个相同的数,因输出最小的排名) 4. 查询排名为x的数 5. 求x的前

2827: 千山鸟飞绝 非旋treap

国际惯例的题面:看起来很不可做的样子,我们先来整理一下题意吧.就是,维护每个点曾经拥有过的最大的两个属性值,支持把点的位置移动.我们用map对每个位置进行离散化,对每个位置建立一个平衡树.为了方便分离,这个平衡树的关键字是节点编号.然后把每个点当做一个节点,放进其所在位置的平衡树里.剩下要做的就是平衡树分离出一个点,合并一个点,还有打标记了.对于士气值的标记,我们维护平衡树中的max,每次合并的时候,用这个新点的威武值去给整棵树打标记,再用树中的max给这个新点打标记.团结值的标记,合并后一起打

非旋 treap 结构体数组版(无指针)详解,有图有真相

非旋  $treap$ (FHQ treap)的简单入门 前置技能 建议在掌握普通 treap 以及 左偏堆(也就是可并堆)食用本blog 原理 以随机数维护平衡,使树高期望为logn级别, FHQ 不依靠旋转,只有两个核心操作merge(合并)和split(拆分) 所谓随机数维护平衡就是给每个节点一个随机值 key (下文中没有加随机的就代表是真实权值), 然后整棵树中 key 值要满足小(大)根堆的性质(也就是heap), 同时也要满足平衡树(tree)的性质(也就是每个节点左子树内节点真实

非旋Treap总结 : 快过Splay 好用过传统Treap

非旋$Treap$ 其高级名字叫$Fhq\ Treap$,既然叫$Treap$,它一定满足了$Treap$的性质(虽然可能来看这篇的人一定知道$Treap$,但我还是多说几句:$Fhp\ Treap$就是继承了$Treap$的随机系统,在二叉搜索的基础上,每个点加一个随机化处理,这些随机值满足堆的性质……通俗一点讲,就是$Fhp\ Treap$它每个点有至少两个值,一个是val,即存的数值,这些数值满足二叉搜索树,也就是父亲比左孩子小/大,则右孩子比父亲小/大:还有一个是key,是个随机值,这些

沉迷数据结构1(treap&amp;非旋treap)

Achen大佬说不要沉迷数据结构否则智商会降低的. 从省选考完后就开始学treap,首先是自己yy了一个打了两百多行,然后debug了2个月还是3个月记不清了. 最后弃疗,去找了网上别人的代码抄了一遍. noip考完后补常规的一段时间,羡慕Achen能20分钟打出一个treap模板,于是自己也开始走上打板子的不归路. 到了后来可以10分钟左右打出一个结构体版的treap,看了Achen的数组版treap,觉得自己结构体版的太不优秀啦,于是就换成数组版的. 然后现在有几周没有碰过treap,感觉又

[BZOJ3223]文艺平衡树 无旋Treap

3223: Tyvj 1729 文艺平衡树 Time Limit: 10 Sec  Memory Limit: 128 MB Description 您需要写一种数据结构(可参考题目标题),来维护一个有序数列,其中需要提供以下操作:翻转一个区间,例如原有序序列是5 4 3 2 1,翻转区间是[2,4]的话,结果是5 2 3 4 1 Input 第一行为n,m n表示初始序列有n个数,这个序列依次是(1,2--n-1,n)  m表示翻转操作次数接下来m行每行两个数[l,r] 数据保证 1<=l<

普通平衡树——非旋转treap

题目: 此为平衡树系列第一道:普通平衡树您需要写一种数据结构,来维护一些数,其中需要提供以下操作:1. 插入x数2. 删除x数(若有多个相同的数,因只删除一个)3. 查询x数的排名(若有多个相同的数,因输出最小的排名)4. 查询排名为x的数5. 求x的前驱(前驱定义为小于x,且最大的数)6. 求x的后继(后继定义为大于x,且最小的数) n<=100000 所有数字均在-107到107内. 输入样例: 10 1 106465 4 1 1 317721 1 460929 1 644985 1 841

4923: [Lydsy1706月赛]K小值查询 平衡树 非旋转Treap

国际惯例的题面:这种维护排序序列,严格大于的进行操作的题都很套路......我们按照[0,k],(k,2k],(2k,inf)分类讨论一下就好.显然第一个区间的不会变化,第二个区间的会被平移进第一个区间,第三个区间的相对大小不会变化.于是我们直接把第二个区间拆了重构,一个一个插入第一个区间即可.因为每次这样做最少减半,所以每个元素只会被重构log次,复杂度nlog^2n.这种按照值域分离区间的操作,非旋转treap实现起来是最简单的......然而第一次写非旋转treap还是出了一点问题,注意它