Tyvj 1728 普通平衡树
Time Limit: 10 Sec Memory Limit: 128 MBSubmit: 17187 Solved: 7501
[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
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
84185
492737
HINT
1.n的数据范围:n<=100000
2.每个数的数据范围:[-2e9,2e9]
题解:是用treap去维护,当然c++的STL也可以过(不知道为什么),
这些都是treap的基本操作,复杂度是O(n log n)的。
1 #include<cstring> 2 #include<cmath> 3 #include<iostream> 4 #include<algorithm> 5 #include<cstdio> 6 7 #define ls tr[p].l 8 #define rs tr[p].r 9 #define N 100007 10 #define inf 2000000010 11 using namespace std; 12 inline int read() 13 { 14 int x=0,f=1;char ch=getchar(); 15 while(ch<'0'||ch>'9'){if (ch=='-')f=-1;ch=getchar();} 16 while(ch>='0'&&ch<='9'){x=(x<<3)+(x<<1)+ch-'0';ch=getchar();} 17 return x*f; 18 } 19 20 int n,sz,rt,ans; 21 struct Node 22 { 23 int l,r,val,siz,rnd,ct;//记录左儿子,右儿子,点值,该子树大小,随机的值,该点值出现的次数。 24 }tr[N];//最多多少个节点,就开多少空间 25 26 inline int rand(){ 27 static int seed = 2333; 28 return seed = (int)((((seed ^ 998244353) + 19260817ll) * 19890604ll) % 1000000007); 29 } 30 inline void update(int p) 31 { 32 tr[p].siz=tr[ls].siz+tr[rs].siz+tr[p].ct; 33 } 34 void lturn(int &p) 35 { 36 int t=tr[p].r;tr[p].r=tr[t].l;tr[t].l=p; 37 tr[t].siz=tr[p].siz;update(p);p=t; 38 } 39 void rturn(int &p) 40 { 41 int t=tr[p].l;tr[p].l=tr[t].r;tr[t].r=p; 42 tr[t].siz=tr[p].siz;update(p);p=t; 43 } 44 void ins(int &p,int x) 45 { 46 if (p==0) 47 { 48 p=++sz; 49 tr[p].siz=tr[p].ct=1,tr[p].val=x,tr[p].rnd=rand(); 50 return; 51 } 52 tr[p].siz++; 53 if (tr[p].val==x) tr[p].ct++; 54 else if (x>tr[p].val) 55 { 56 ins(tr[p].r,x); 57 if (tr[rs].rnd<tr[p].rnd) lturn(p); 58 }else 59 { 60 ins(tr[p].l,x); 61 if (tr[ls].rnd<tr[p].rnd) rturn(p); 62 } 63 } 64 void del(int &p,int x) 65 { 66 if (p==0) return; 67 if (tr[p].val==x) 68 { 69 if (tr[p].ct>1) tr[p].ct--,tr[p].siz--;//如果有多个直接减一即可。 70 else 71 { 72 if (ls==0||rs==0) p=ls+rs;//单节点或者空的话直接儿子移上来或者删去即可。 73 else if (tr[ls].rnd<tr[rs].rnd) rturn(p),del(p,x); 74 else lturn(p),del(p,x); 75 } 76 } 77 else if (x>tr[p].val) tr[p].siz--,del(rs,x); 78 else tr[p].siz--,del(ls,x); 79 } 80 int find_pm(int p,int x) 81 { 82 if (p==0) return 0; 83 if (tr[p].val==x) return tr[ls].siz+1; 84 if (x>tr[p].val) return tr[ls].siz+tr[p].ct+find_pm(rs,x); 85 else return find_pm(ls,x); 86 } 87 int find_sz(int p,int x) 88 { 89 if (p==0) return 0; 90 if (x<=tr[ls].siz) return find_sz(ls,x); 91 x-=tr[ls].siz; 92 if (x<=tr[p].ct) return tr[p].val; 93 x-=tr[p].ct; 94 return find_sz(rs,x); 95 } 96 int find_qq(int p,int x) 97 { 98 if (p==0) return -inf; 99 if (tr[p].val<x) return max(tr[p].val,find_qq(rs,x)); 100 else if (tr[p].val>=x) return find_qq(ls,x); 101 } 102 int find_hj(int p,int x) 103 { 104 if (p==0) return inf; 105 if (tr[p].val<=x) return find_hj(rs,x); 106 else return min(tr[p].val,find_hj(ls,x)); 107 } 108 int main() 109 { 110 n=read(); 111 for (int i=1;i<=n;i++) 112 { 113 int flag=read(),x=read(); 114 if (flag==1) ins(rt,x); 115 if (flag==2) del(rt,x); 116 if (flag==3) printf("%d ",find_pm(rt,x));//寻找x的排名 117 if (flag==4) printf("%d ",find_sz(rt,x));//寻找排名为x的数字 118 if (flag==5) printf("%d ",find_qq(rt,x)); 119 if (flag==6) printf("%d ",find_hj(rt,x)); 120 } 121 }