码迷,mamicode.com
首页 > 其他好文 > 详细

P3369 【模板】普通平衡树(Treap/SBT)

时间:2018-02-28 21:35:13      阅读:141      评论:0      收藏:0      [点我收藏+]

标签:getchar   scanf   set   个数   reg   blank   using   family   暴力   

题目描述

您需要写一种数据结构(可参考题目标题),来维护一些数,其中需要提供以下操作:

  1. 插入x数

  2. 删除x数(若有多个相同的数,因只删除一个)

  3. 查询x数的排名(排名定义为比当前数小的数的个数+1。若有多个相同的数,因输出最小的排名)

  4. 查询排名为x的数

  5. 求x的前驱(前驱定义为小于x,且最大的数)

  6. 求x的后继(后继定义为大于x,且最小的数)

输入输出格式

输入格式:

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

输出格式:

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

输入输出样例

输入样例#1:
10
1 106465
4 1
1 317721
1 460929
1 644985
1 84185
1 89851
6 81968
1 492737
5 493598
输出样例#1:
106465
84185
492737

说明

时空限制:1000ms,128M

1.n的数据范围: n≤100000

2.每个数的数据范围: [−107,107]

来源:Tyvj1728 原名:普通平衡树

在此鸣谢

 

Solution:

本题需要的6种操作的splay实现原理见

splay代码:

  1 #include<cstdio>
  2 #define N 100010
  3 using namespace std;
  4 
  5 int fa[N],ch[N][2],siz[N],cnt[N],date[N],root,nn,n,tot;
  6 
  7 int son(int x) {
  8     return x==ch[fa[x]][1];
  9 }
 10 
 11 void pushup(int rt) {
 12     int l=ch[rt][0],r=ch[rt][1];
 13     siz[rt]=siz[l]+siz[r]+cnt[rt];
 14 }
 15 
 16 void rotate(int x) {
 17    int y=fa[x],z=fa[y],b=son(x),c=son(y),a=ch[x][!b];
 18    if(z)ch[z][c]=x;else root=x;fa[x]=z;
 19    if(a)fa[a]=y;ch[y][b]=a;
 20    ch[x][!b]=y;fa[y]=x;///
 21    pushup(y);pushup(x);    
 22 }
 23 
 24 void splay(int x,int i) {
 25     while(fa[x]!=i) {
 26         int y=fa[x],z=fa[y];
 27         if(z==i) {
 28             rotate(x);
 29         } else {
 30             if(son(x)==son(y)) {
 31                 rotate(y);rotate(x);
 32             } else {
 33                 rotate(x);rotate(x);
 34             }
 35         }
 36     }
 37 }
 38 
 39 void ins(int &rt,int x) {
 40     if(rt==0) {
 41         rt=++nn;
 42         date[nn]=x;
 43         siz[nn]=cnt[nn]=1;
 44         return;
 45     }
 46     if(x==date[rt]) {
 47         cnt[rt]++;siz[rt]++;
 48         return;
 49     }
 50     if(x<date[rt]) {
 51         ins(ch[rt][0],x);
 52         fa[ch[rt][0]]=rt;
 53         pushup(rt);
 54     } else {
 55         ins(ch[rt][1],x);
 56         fa[ch[rt][1]]=rt;
 57         pushup(rt);
 58     }
 59 }
 60 
 61 int getpre(int rt,int x) {
 62     int p=rt,ans;
 63     while(p) {
 64       if(x<=date[p]) {
 65           p=ch[p][0];///
 66       } else {
 67           ans=p;
 68           p=ch[p][1];
 69       }
 70     }
 71     return ans;
 72 }
 73 
 74 int getsuc(int rt,int x) {
 75     int p=rt,ans;
 76     while(p) {
 77         if(x>=date[p]) {
 78             p=ch[p][1];
 79         } else {
 80             ans=p;
 81             p=ch[p][0];
 82         }
 83     }
 84     return ans;
 85 }
 86 
 87 int getmn(int rt) {
 88     int p=rt,ans=-1;
 89     while(p) {
 90         ans=p;
 91         p=ch[p][0];
 92     }
 93     return ans;
 94 }
 95 
 96 void del(int rt,int x) {
 97     if(date[rt]==x) {
 98         if(cnt[rt]>1) {
 99             cnt[rt]--;siz[rt]--;
100         } else {
101             splay(rt,0);
102             int p=getmn(ch[rt][1]);
103             if(p!=-1) {
104                 splay(p,rt);
105                 root=p;fa[p]=0;
106                 ch[p][0]=ch[rt][0];fa[ch[rt][0]]=p;
107                 pushup(p);
108             } else {
109                 root=ch[rt][0];fa[ch[rt][0]]=0;
110             }
111         }
112         return;
113     }
114     if(x<date[rt]) {
115         del(ch[rt][0],x);
116         pushup(rt);///
117     } else {
118         del(ch[rt][1],x);
119         pushup(rt);
120     }
121 }
122 
123 int getk(int rt,int k) {
124     if(date[rt]==k) {
125         splay(rt,0);
126         if(ch[rt][0]==0) {
127             return 1;
128         } else {
129             return siz[ch[rt][0]]+1;
130         }
131     }
132     if(k<date[rt]) return getk(ch[rt][0],k);
133     else return getk(ch[rt][1],k);
134 }
135 
136 int getkth(int rt,int k) {
137     int l=ch[rt][0];
138     if(siz[l]+1<=k&&k<=siz[l]+cnt[rt]) return date[rt];
139     if(k<siz[l]+1) return getkth(ch[rt][0],k);
140     if(siz[l]+cnt[rt]<k) return getkth(ch[rt][1],k-(siz[l]+cnt[rt]));
141 }
142 
143 int main() {
144     scanf("%d",&n);
145     while(n--) {
146         int opt,x;
147         scanf("%d%d",&opt,&x);
148         if(opt==1) {
149             tot++;
150             ins(root,x);
151         }
152         if(opt==2) {
153             tot--;
154             del(root,x);
155         }
156         if(opt==3) {
157             printf("%d\n",getk(root,x));
158         }
159         if(opt==4) {
160             printf("%d\n",getkth(root,x));
161         }
162         if(opt==5) {
163             printf("%d\n",date[getpre(root,x)]);
164         }
165         if(opt==6) {
166             printf("%d\n",date[getsuc(root,x)]);
167         }
168     }
169     return 0;
170 }

 

本题用Treap的实现:引用自hzwer的博客

这是一道平衡树的模板题

treap是一棵修改了结点顺序的二叉查找树

通常树内的每个结点x都有一个关键字值key[x],另外,还要为结点分配一个随机数。

假设所有的优先级是不同的,所有的关键字也是不同的。treap的结点排列成让关键字遵循二叉查找树性质,并且优先级遵

循最小堆顺序性质:
1.如果v是u的左孩子,则key[v] < key[u].
2.如果v是u的右孩子,则key[v] > key[u].
3.如果v是u的孩子,则rand[u] > rand[u].
这两个性质的结合就是为什么这种树被称为“treap”的原因,因为它同时具有二叉查找树和heap的特征。

Treap代码:

 

  1 #include<cstdio>
  2 #include<cstdlib>
  3 #include<ctime>
  4 using namespace std;
  5 const int N=1e6+10;
  6 struct tree{
  7     int l,r;//左右儿子节点编号 
  8     int num;//当前节点的数字 
  9     int s;//以当前节点为根的子树的节点数 
 10     int sum;//当前节点的数字的数量 
 11     int rnd;//随机优先级 
 12 }tr[N];//下标为节点编号 
 13 int n,rt,cnt,t1,t2;
 14 void updata(int &k){
 15     int &l=tr[k].l,&r=tr[k].r;
 16     tr[k].s=tr[l].s+tr[r].s+tr[k].sum;
 17 }
 18 void lturn(int &k){
 19     int t=tr[k].r;tr[k].r=tr[t].l;tr[t].l=k;
 20     tr[t].s=tr[k].s;updata(k);k=t;
 21 }
 22 void rturn(int &k){
 23     int t=tr[k].l;tr[k].l=tr[t].r;tr[t].r=k;
 24     tr[t].s=tr[k].s;updata(k);k=t;
 25 }
 26 void insert(int &k,int x){
 27     if(!k){
 28         k=++cnt;tr[k].num=x;tr[k].s=1;tr[k].sum++;tr[k].rnd=rand();return ;
 29     }
 30     tr[k].s++;
 31     int &l=tr[k].l,&r=tr[k].r;
 32     if(x<tr[k].num){
 33         insert(l,x);
 34         if(tr[l].rnd<tr[k].rnd) rturn(k);
 35     }
 36     else if(x>tr[k].num){
 37         insert(r,x);
 38         if(tr[r].rnd<tr[k].rnd) lturn(k);
 39     }
 40     else{
 41         tr[k].sum++;return ;
 42     }
 43 }
 44 void del(int &k,int x){
 45     if(!k) return ;
 46     int &l=tr[k].l,&r=tr[k].r;
 47     if(x==tr[k].num){
 48         if(tr[k].sum>1){
 49             tr[k].sum--;tr[k].s--;return ;
 50         }
 51         if(l*r==0) k=l+r;
 52         else{
 53             if(tr[l].rnd<tr[r].rnd) rturn(k);
 54             else lturn(k);
 55             del(k,x);
 56         }
 57     }
 58     else{
 59         tr[k].s--;
 60         if(x>tr[k].num) del(r,x);
 61         else del(l,x);
 62     }
 63 }
 64 int find1(int &k,int x){
 65     if(!k) return 0;
 66     int &l=tr[k].l,&r=tr[k].r;
 67     if(tr[k].num==x) return tr[l].s+1;
 68     if(tr[k].num>x) return find1(l,x);
 69     if(tr[k].num<x) return tr[l].s+tr[k].sum+find1(r,x);
 70 }
 71 int find2(int &k,int x){
 72     if(!k) return 0;
 73     int &l=tr[k].l,&r=tr[k].r;
 74     if(tr[l].s+1<=x&&tr[l].s+tr[k].sum>=x) return tr[k].num;
 75     if(tr[l].s>=x) return find2(l,x);
 76     if(tr[l].s+tr[k].sum<x) return find2(r,x-tr[l].s-tr[k].sum);
 77 }
 78 void pred(int &k,int x){
 79     if(!k) return ;
 80     int &l=tr[k].l,&r=tr[k].r;
 81     if(tr[k].num<x){
 82         t1=tr[k].num;
 83         pred(r,x);
 84     }
 85     else pred(l,x);
 86 }
 87 void succ(int &k,int x){
 88     if(!k) return ;
 89     int &l=tr[k].l,&r=tr[k].r;
 90     if(tr[k].num>x){
 91         t2=tr[k].num;
 92         succ(l,x);
 93     }
 94     else succ(r,x);
 95 }
 96 int main(){
 97     srand(time(0));
 98     scanf("%d",&n);
 99     for(int i=1,opt,x;i<=n;i++){
100         scanf("%d%d",&opt,&x);t1=t2=0;
101         switch(opt){
102             case 1:insert(rt,x);break;
103             case 2:del(rt,x);break;
104             case 3:printf("%d\n",find1(rt,x));break;
105             case 4:printf("%d\n",find2(rt,x));break;
106             case 5:pred(rt,x);printf("%d\n",t1);break;
107             case 6:succ(rt,x);printf("%d\n",t2);break;
108         }
109     }
110     return 0;
111 }

 

用vector暴力模拟可以AC,总耗时也就比正解慢100ms左右

vector代码:

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<cstdlib>
 4 #include<set>
 5 #include<vector>
 6 #include<algorithm>
 7 #define inf 1000000000
 8 using namespace std;
 9 inline int read()
10 {
11     int x=0,f=1;char ch=getchar();
12     while(ch<0||ch>9){if(ch==-)f=-1;ch=getchar();}
13     while(ch>=0&&ch<=9){x=x*10+ch-0;ch=getchar();}
14     return x*f;
15 }
16 int n;
17 vector<int> a;
18 void insert(int x)
19 {
20     a.insert(upper_bound(a.begin(),a.end(),x),x);
21     return;
22 }
23 void del(int x)
24 {
25     a.erase(lower_bound(a.begin(),a.end(),x));
26     return;
27 }
28 int find(int x)
29 {
30     return lower_bound(a.begin(),a.end(),x)-a.begin()+1;
31 }
32 int main()
33 {
34     n=read();
35     a.reserve(200000);
36     int f,x;
37     for(int i=1;i<=n;i++)
38     {
39         f=read();x=read();
40         switch(f)
41         {
42         case 1:insert(x);break;
43         case 2:del(x);break;
44         case 3:printf("%d\n",find(x));break;
45         case 4:printf("%d\n",a[x-1]);break;
46         case 5:printf("%d\n",*--lower_bound(a.begin(),a.end(),x));break;
47         case 6:printf("%d\n",*upper_bound(a.begin(),a.end(),x));break;
48         }
49     }
50     return 0;
51 }

用pbds中的红黑树的AC实现代码(竟然比vector的暴力模拟还慢上100ms,贼有意思!):

 1 #include<bits/stdc++.h>
 2 #include<ext/pb_ds/tree_policy.hpp>
 3 #include<ext/pb_ds/assoc_container.hpp>
 4 #define ll long long
 5 #define il inline
 6 using namespace std;
 7 using namespace __gnu_pbds;
 8 typedef tree<ll,null_type,less<ll>,rb_tree_tag,tree_order_statistics_node_update>t;
 9 il int gi()
10 {
11     int a=0;char x=getchar();bool f=0;
12     while((x<0||x>9)&&x!=-)x=getchar();
13     if(x==-)x=getchar(),f=1;
14     while(x>=0&&x<=9)a=a*10+x-48,x=getchar();
15     return f?-a:a;
16 }
17 ll n,opt,x,ans;
18 int main()
19 {
20     t T;
21     n=gi();
22     for(int i=1;i<=n;i++){
23         opt=gi(),x=gi();
24         if(opt==1)T.insert((x<<20)+i);
25         if(opt==2)T.erase(T.lower_bound(x<<20));
26         if(opt==3)printf("%lld\n",T.order_of_key(x<<20)+1);
27         if(opt==4){ans=*T.find_by_order(x-1),printf("%lld\n",ans>>20);}
28         if(opt==5){ans=*--T.lower_bound(x<<20),printf("%lld\n",ans>>20);}
29         if(opt==6){ans=*T.upper_bound((x<<20)+n),printf("%lld\n",ans>>20);}
30 
31     }
32     return 0;
33 }

 

 

 

 

P3369 【模板】普通平衡树(Treap/SBT)

标签:getchar   scanf   set   个数   reg   blank   using   family   暴力   

原文地址:https://www.cnblogs.com/five20/p/8485642.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!