[BZOJ3224]普通平衡树(旋转treap)

3224: Tyvj 1728 普通平衡树

Time Limit: 10 Sec  Memory Limit: 128 MB
Submit: 20328  Solved: 8979
[Submit][Status][Discuss]

Description

您需要写一种数据结构(可参考题目标题),来维护一些数,其中需要提供以下操作:
1. 插入x数
2. 删除x数(若有多个相同的数,因只删除一个)
3. 查询x数的排名(若有多个相同的数,因输出最小的排名)
4. 查询排名为x的数
5. 求x的前驱(前驱定义为小于x,且最大的数)
6. 求x的后继(后继定义为大于x,且最小的数)

Input

第一行为n,表示操作的个数,下面n行每行有两个数opt和x,opt表示操作的序号(1<=opt<=6)

Output

对于操作3,4,5,6每行输出一个数,表示对应答案

Sample Input

10
1 106465
4 1
1 317721
1 460929
1 644985
1 84185
1 89851
6 81968
1 492737
5 493598

Sample Output

106465
84185
492737

HINT

1.n的数据范围:n<=100000

2.每个数的数据范围:[-2e9,2e9]

Source

[Submit][Status][Discuss]

刷点模板题。。发现自己treap忘光了。。

没什么好说的,题目里的排名是指从小到大,其余没有什么坑点,那些作为函数哪些作为过程要想清楚。

比无旋treap快,所以说到现在都没有遇上必须用无旋treap的题,除了WC的那道可持久化treap。

 1 #include<cstdio>
 2 #include<cstdlib>
 3 #include<cstring>
 4 #include<algorithm>
 5 #define rep(i,l,r) for (int i=l; i<=r; i++)
 6 using namespace std;
 7
 8 const int N=100100,inf=1000000000;
 9 int n,rt,nd,ans,op,x,ls[N],rs[N],sz[N],h[N],v[N],w[N];
10
11 void rrot(int &x){
12     int y=ls[x]; ls[x]=rs[y]; rs[y]=x;
13     sz[y]=sz[x]; sz[x]=sz[ls[x]]+sz[rs[x]]+w[x]; x=y;
14 }
15
16 void lrot(int &x){
17     int y=rs[x]; rs[x]=ls[y]; ls[y]=x;
18     sz[y]=sz[x]; sz[x]=sz[ls[x]]+sz[rs[x]]+w[x]; x=y;
19 }
20
21 void ins(int &x,int k){
22     if (!x){
23         x=++nd; v[x]=k; h[x]=rand(); sz[x]=w[x]=1; return;
24     }
25     sz[x]++;
26     if (v[x]==k) { w[x]++; return; }
27     if (k<v[x]){ ins(ls[x],k); if (h[ls[x]]<h[x]) rrot(x);}
28      else { ins(rs[x],k); if (h[rs[x]]<h[x]) lrot(x); }
29 }
30
31 void del(int &x,int k){
32     if (v[x]==k){
33         if (w[x]>1) { w[x]--; sz[x]--; return; }
34         if (!ls[x] || !rs[x]) { x=ls[x]+rs[x]; return; }
35         if (h[ls[x]]<h[rs[x]]) rrot(x),del(x,k); else lrot(x),del(x,k);
36         return;
37     }
38     sz[x]--;
39     if (k<v[x]) del(ls[x],k); else del(rs[x],k);
40 }
41
42 int get(int x,int k){
43     if (!x) return 0;
44     if (v[x]==k) return sz[ls[x]]+1;
45     else if (k<v[x]) return get(ls[x],k); else return sz[ls[x]]+w[x]+get(rs[x],k);
46 }
47
48 int find(int x,int k){
49     if (!x) return 0;
50     if (sz[ls[x]]+1<=k && sz[ls[x]]+w[x]>=k) return v[x];
51     if (sz[ls[x]]>=k) return find(ls[x],k);
52         else return find(rs[x],k-sz[ls[x]]-w[x]);
53 }
54
55 void pre(int x,int k){
56     if (!x) return;
57     if (v[x]<k) ans=max(ans,v[x]),pre(rs[x],k); else pre(ls[x],k);
58 }
59
60 void nxt(int x,int k){
61     if (!x) return;
62     if (v[x]>k) ans=min(ans,v[x]),nxt(ls[x],k); else nxt(rs[x],k);
63 }
64
65 int main(){
66     freopen("bzoj3224.in","r",stdin);
67     freopen("bzoj3224.out","w",stdout);
68     for (scanf("%d",&n); n--; ){
69         scanf("%d%d",&op,&x);
70         if (op==1) ins(rt,x);
71         if (op==2) del(rt,x);
72         if (op==3) printf("%d\n",get(rt,x));
73         if (op==4) printf("%d\n",find(rt,x));
74         if (op==5) ans=0,pre(rt,x),printf("%d\n",ans);
75         if (op==6) ans=inf,nxt(rt,x),printf("%d\n",ans);
76     }
77     return 0;
78 }

原文地址:https://www.cnblogs.com/HocRiser/p/8763251.html

时间: 2024-10-09 21:10:42

[BZOJ3224]普通平衡树(旋转treap)的相关文章

平衡树讲解(旋转treap,非旋转treap,splay)

在刷了许多道平衡树的题之后,对平衡树有了较为深入的理解,在这里和大家分享一下,希望对大家学习平衡树能有帮助. 平衡树有好多种,比如treap,splay,红黑树,STL中的set.在这里只介绍几种常用的:treap和splay(其中treap包括旋转treap和非旋转treap). 一.treap treap这个词是由tree和heap组合而成,意思是树上的的堆(其实就是字面意思啦qwq).treap可以说是由二叉搜索树(BST)进化而来,二叉搜索树每个点满足它左子树中所有点权值都比它小,它右子

普通平衡树——非旋转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还是出了一点问题,注意它

[bzoj1895][Pku3580]supermemo_非旋转Treap

supermemo bzoj-1895 Pku-3580 题目大意:给定一个n个数的序列,需支持:区间加,区间翻转,区间平移,单点插入,单点删除,查询区间最小值. 注释:$1\le n\le 6.1\cdot 10^6$. 想法: 这数据范围给的我真是醉了. 显然用平衡树,这里用非旋转Treap,题目让你干什么你就干什么. 区间加:撕出子树区间后打标记维护区间加. 区间翻转:撕出子树区间后打标记维护区间翻转. 区间平移:相当于两段相邻区间交换,所以撕成四部分:左边,第一个区间,第二个区间,右边.

非旋转Treap详解

利用其他人其中考试的时间,终于学完了非旋转Treap,它与普通Treap的区别就是它不旋转废话.前置知识只有BST和可并堆. BST看这个博客,解释的挺清楚的.https://www.cnblogs.com/jiangminghong/p/9999884.html 可并堆就是用很快的时间合并两个堆.如果裸上一个并查集的话就是nlog2n.这个复杂度我们是不能接受的.正常的可并堆是维护一棵左偏树,我们用一个参数dis[x]表示从x点出发能够向右走的最大步数.每次两个堆合并时,我们就把一个堆扔到另一

数组splay ------ luogu P3369 【模板】普通平衡树(Treap/SBT)

二次联通门 : luogu P3369 [模板]普通平衡树(Treap/SBT) #include <cstdio> #define Max 100005 #define Inline __attri\ bute__( ( optimize( "-O2" ) ) ) Inline void read (int &now) { now = 0; register char word = getchar (); bool temp = false; while (wor

非旋转Treap

Treap是一种平衡二叉树,同时也是一个堆.它既具有二叉查找树的性质,也具有堆的性质.在对数据的查找.插入.删除.求第k大等操作上具有期望O(log2n)的复杂度.     Treap可以通过节点的旋转来实现其维持平衡的操作,详见旋转式Treap. 而旋转式Treap在对区间数据的操作上无能为力,这就需要非旋转式Treap来解决这些区间问题. 非旋转式Treap支持的操作 基本操作: 操作 说明 实现复杂度 Build 构造Treap O(n) Merge 合并Treap O(log2n) Sp

替罪羊树 ------ luogu P3369 【模板】普通平衡树(Treap/SBT)

二次联通门 : luogu P3369 [模板]普通平衡树(Treap/SBT) 闲的没事,把各种平衡树都写写 比较比较... 下面是替罪羊树 #include <cstdio> #include <vector> #define Max_ 100010 #define Inline __attri\ bute__( ( optimize( "-O2" ) ) ) Inline void read (int &now) { register char w

红黑树 ------ luogu P3369 【模板】普通平衡树(Treap/SBT)

二次联通门 : luogu P3369 [模板]普通平衡树(Treap/SBT) 近几天闲来无事...就把各种平衡树都写了一下... 下面是红黑树(Red Black Tree) #include <cstdio> #define Max 100001 #define Red true #define Black false #define Inline __attri\ bute__( ( optimize( "-O2" ) ) ) Inline void read (i