很明显这是一道treap的题,但看了黄学长的博客后,也让我大开了眼界,没想到vector也能用那么短的编码量把这道题AC,着实令我敬佩。这也提醒了我 STL 的重要性。 的确, 对于C++ 选手来说,如果能灵活地使用 STL, 的确受益匪浅(虽然速度可能比其他的慢一点,但正确性和编程复杂度都比其他的好,如果时间复杂度允许,在紧张的编程时间内,STL或许会是不错的选择)。
这是STL(vector)的代码, 用到了 insert, lowerr_bound, erase 等函数, 加油。(1700多毫秒)
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<cstdlib> 5 #include<set> 6 #include<vector> 7 #include<algorithm> 8 #define inf 1000000000 9 using namespace std; 10 11 inline int read() 12 { 13 int x=0,f=1;char ch=getchar(); 14 while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();} 15 while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();} 16 return x*f; 17 } 18 int n; 19 vector<int> a; 20 21 void insert(int x) 22 { 23 a.insert(upper_bound(a.begin(),a.end(),x),x); 24 return; 25 } 26 27 void del(int x) 28 { 29 a.erase(lower_bound(a.begin(),a.end(),x)); 30 return; 31 } 32 int find(int x) 33 { 34 return lower_bound(a.begin(),a.end(),x)-a.begin()+1; 35 } 36 int main() 37 { 38 n=read(); 39 a.reserve(200000); 40 int f,x; 41 for(int i=1;i<=n;i++) 42 { 43 f=read();x=read(); 44 switch(f) 45 { 46 case 1:insert(x);break; 47 case 2:del(x);break; 48 case 3:printf("%d ",find(x));break; 49 case 4:printf("%d ",a[x-1]);break; 50 case 5:printf("%d ",*--lower_bound(a.begin(),a.end(),x));break; 51 case 6:printf("%d ",*upper_bound(a.begin(),a.end(),x));break; 52 } 53 } 54 return 0; 55 }
接下来肯定是treap 的代码了,orz 黄学长。从他那里,着实学了不少好东西。(300多毫秒,比上面快多了吧!这个时间差距主要是因为查如何删除造成的)。
1 #include<cstdio> 2 #include<iostream> 3 #include<cstdlib> 4 #define rep(i,j,k) for(int i = j; i <= k; i++) 5 using namespace std; 6 7 struct node{ 8 int c[2], w, s, v, rnd; 9 } tr[100005]; 10 11 int n, ans, root, size; 12 13 int read() 14 { 15 int s = 0, t = 1; char c= getchar(); 16 while( !isdigit(c) ){ 17 if( c == '-' ) t = -1; c = getchar(); 18 } 19 while( isdigit(c) ){ 20 s = s * 10 + c - '0'; c = getchar(); 21 } 22 return s * t; 23 } 24 25 void update(int k) 26 { 27 tr[k].s = tr[tr[k].c[0]].s + tr[tr[k].c[1]].s + tr[k].w; 28 } 29 30 void rorate(int&k,int d) 31 { 32 int y = tr[k].c[d^1]; tr[k].c[d^1] = tr[y].c[d]; 33 tr[y].c[d] = k; update(k), update(y), k = y; 34 } 35 36 void insert(int&k,int x) 37 { 38 if( k == 0 ){ 39 ++size; k = size; tr[k].c[0] = tr[k].c[1] = 0, tr[k].s = tr[k].w = 1, tr[k].v = x, tr[k].rnd = rand(); 40 return; 41 } 42 tr[k].s++; 43 if( x == tr[k].v ) tr[k].w++; 44 else if( x < tr[k].v) { 45 insert(tr[k].c[0],x); 46 if( tr[tr[k].c[0]].rnd > tr[k].rnd )rorate(k,1); 47 } 48 else { 49 insert(tr[k].c[1],x); 50 if( tr[tr[k].c[1]].rnd > tr[k].rnd ) rorate(k,0); 51 } 52 } 53 54 void delt(int&k,int x) 55 { 56 if( !k ) return; 57 if( tr[k].v == x ){ 58 if( tr[k].w > 1 ) { 59 tr[k].w--, tr[k].s--; return; 60 } 61 else { 62 if( tr[k].c[0] * tr[k].c[1] == 0 ) k = tr[k].c[0] + tr[k].c[1]; 63 else { 64 if( tr[tr[k].c[0]].rnd > tr[tr[k].c[1]].rnd ) { 65 rorate(k,1); delt(k,x); 66 } 67 else { 68 rorate(k,0); delt(k,x); 69 } 70 } 71 } 72 } 73 else { 74 tr[k].s--; 75 if( x < tr[k].v ) delt(tr[k].c[0],x); 76 else delt(tr[k].c[1],x); 77 } 78 } 79 80 int query_rank(int k,int x) 81 { 82 if( !k ) return 0; 83 if( tr[k].v == x ) return tr[tr[k].c[0]].s + 1; 84 else if( tr[k].v < x ) return tr[tr[k].c[0]].s + tr[k].w + query_rank(tr[k].c[1],x); 85 else return query_rank(tr[k].c[0],x); 86 } 87 88 int query_num(int k,int num) 89 { 90 if( !k ) return 0; 91 if( tr[tr[k].c[0]].s >= num ) return query_num(tr[k].c[0],num); 92 else if( tr[tr[k].c[0]].s + tr[k].w < num ) return query_num(tr[k].c[1],num-tr[tr[k].c[0]].s - tr[k].w); 93 else return tr[k].v; 94 } 95 96 void query_pre(int k,int x) 97 { 98 if( !k ) return; 99 if( tr[k].v < x ){ 100 ans = k, query_pre(tr[k].c[1],x); 101 } 102 else query_pre(tr[k].c[0],x); 103 } 104 105 void query_suc(int k,int x) 106 { 107 if( !k ) return; 108 if( tr[k].v > x ){ 109 ans = k, query_suc(tr[k].c[0],x); 110 } 111 else query_suc(tr[k].c[1],x); 112 } 113 114 int main() 115 { 116 scanf("%d",&n); 117 int opt,x; 118 for(int i=1;i<=n;i++) 119 { 120 scanf("%d%d",&opt,&x); 121 switch(opt) 122 { 123 case 1:insert(root,x);break; 124 case 2:delt(root,x);break; 125 case 3:printf("%d ",query_rank(root,x));break; 126 case 4:printf("%d ",query_num(root,x));break; 127 case 5:ans=0;query_pre(root,x);printf("%d ",tr[ans].v);break; 128 case 6:ans=0;query_suc(root,x);printf("%d ",tr[ans].v);break; 129 } 130 } 131 return 0; 132 }
3224: Tyvj 1728 普通平衡树
Time Limit: 10 Sec Memory Limit: 128 MBSubmit: 5783 Solved: 2381
[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.每个数的数据范围:[-1e7,1e7]