山东济南彤昌机械科技有限公司 山东济南江鹏工贸游有限公司

bzoj3224 Tyvj 1728 普通平衡树(名次树+处理相同)

3224: Tyvj 1728 普通平衡树

Time Limit: 10 Sec  Memory Limit: 128 MB
Submit: 5354  Solved: 2196
[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.每个数的数据范围:[-1e7,1e7]

 

【思路】

    Rank tree

    Treap实现名次树。需要多维护s,w域分别表示节点数目与相同键值的数目,相应修改maintain,remove和rank操作。

    需要注意的是不能单单在insert的时候安排相同结点放在右子,因为有可能结点通过旋转转上来,这就违反了我们的初衷。

【代码】

 1 #include<cstdio>
 2 #include<ctime>
 3 #include<cstring>
 4 #include<cstdlib>
 5 #include<iostream>
 6 #define FOR(a,b,c) for(int a=(b);a<=(c);a++)
 7 using namespace std;
 8 
 9 struct Node{
10     Node* ch[2];
11     int v,r,s,w;
12     Node(int x):v(x) { ch[0]=ch[1]=NULL; s=w=1; r=rand(); }
13     void maintain() {
14         s=w;                                    //change
15         if(ch[0]!=NULL) s+=ch[0]->s;
16         if(ch[1]!=NULL) s+=ch[1]->s;
17     }
18     int cmp(int x) const {
19         if(x==v) return -1;  return x<v?0:1; 
20     }
21 };
22 void rotate(Node* &o,int d) {
23     Node* k=o->ch[d^1]; o->ch[d^1]=k->ch[d]; k->ch[d]=o;
24     o->maintain(); k->maintain(); o=k;
25 }
26 //不能只是把大于等于x的放在右子树 有可能旋上来
27 void insert(Node* &o,int x) {
28     if(o==NULL) o=new Node(x);
29     else {
30         int d=o->cmp(x);
31         if(d==-1) { o->w++; o->maintain(); return;    }    //相同键值的个数 
32         insert(o->ch[d],x);
33         if(o->ch[d]->r > o->r) rotate(o,d^1);
34     }
35     o->maintain();
36 }
37 void remove(Node* &o,int x){
38     if(o==NULL) return ;
39     int d=o->cmp(x);
40     if(d==-1) {
41         Node* u=o;
42         if(o->w>1) { o->w--; o->maintain(); return ; }  //change2
43         if(o->ch[0]!=NULL && o->ch[1]!=NULL) {
44             int d2=o->ch[0]->r > o->ch[1]->r? 1:0;
45             rotate(o,d2); remove(o->ch[d2],x);
46         }
47         else {
48             if(o->ch[0]!=NULL) o=o->ch[0]; else o=o->ch[1];
49             delete u;
50         }
51     }
52     else remove(o->ch[d],x);
53     if(o!=NULL) o->maintain();
54 }
55 int kth(Node* o,int k) {
56     if(o==NULL || k<=0 || k>o->s) return 0;
57     int s=o->ch[0]==NULL? 0:o->ch[0]->s,w=o->w;
58     if(s+1<=k && k<=s+w) return o->v;
59     else if(k<=s) return kth(o->ch[0],k);
60     else return kth(o->ch[1],k-s-w);
61 }
62 int rank(Node* o,int x) {
63     if(o==NULL) return 0;
64     int d=o->cmp(x),s=o->ch[0]==NULL?0:o->ch[0]->s;
65     int f= d==1? s+o->w:0;
66     if(d==-1) return s+1;
67     else return rank(o->ch[d],x)+f;
68 }
69 void query1(Node* o,int x,int& ans) {
70     if(o==NULL) return ;
71     if(o->v<x) { ans=o->v; query1(o->ch[1],x,ans); }
72     else query1(o->ch[0],x,ans);
73 }
74 void query2(Node* o,int x,int& ans) {
75     if(o==NULL) return ;
76     if(o->v>x) { ans=o->v; query2(o->ch[0],x,ans); }
77     else query2(o->ch[1],x,ans);
78 }
79 int n,opt,x,ans;
80 Node* root=NULL;
81 
82 int main() {
83     //srand(time(0));    //bzoj上不要用 否则RE 
84     scanf("%d",&n);
85     FOR(i,1,n) {
86         scanf("%d%d",&opt,&x);
87         switch(opt) {
88             case 1:  insert(root,x);  break;
89             case 2:  remove(root,x);  break;
90             case 3:  printf("%d\n",rank(root,x));   break;
91             case 4:  printf("%d\n",kth(root,x));    break;
92             case 5:  ans=0;  query1(root,x,ans); printf("%d\n",ans);   break;
93             case 6:  ans=0;  query2(root,x,ans); printf("%d\n",ans);   break;
94         }
95     }
96     return 0;
97 }

 

posted on 2015-12-04 14:16  hahalidaxin  阅读(236)  评论(0编辑  收藏  举报