平衡树模板

1829. [Tyvj 1728]普通平衡树

★★★   输入文件:phs.in   输出文件:phs.out   简单对比
时间限制:1 s   内存限制:128 MB

【题目描述】

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

【输入格式】

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

【输出格式】

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

【样例输入】

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

【样例输出】

106465
84185
492737

【提示】

1.n的数据范围:n<=100000
2.每个数的数据范围:[-1e7,1e7]
 
【Treap】
cojs上测试:运行时间 0.129 s      内存使用 2.63 MiB
 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstdlib>
 4 using namespace std;
 5 struct data{int l,r,v,size,fix,w;}tr[100005];
 6 int n,len,root,ans;
 7 char buf[1<<15],*fs,*ft;
 8 inline char getc() {return (fs==ft&&(ft=(fs=buf)+fread(buf,1,1<<15,stdin),fs==ft))?0:*fs++;}
 9 inline int read()
10 {
11     int x=0,f=1;  char ch=getc();
12     while(!isdigit(ch))  {if(ch=='-')  f=-1;  ch=getc();}
13     while(isdigit(ch))  {x=x*10+ch-'0';  ch=getc();}
14     return x*f;
15 }
16 void update(int k){tr[k].size=tr[tr[k].l].size+tr[tr[k].r].size+tr[k].w;}
17 void rturn(int &k){int t=tr[k].l;tr[k].l=tr[t].r;tr[t].r=k;tr[t].size=tr[k].size;update(k);k=t;}
18 void lturn(int &k){int t=tr[k].r;tr[k].r=tr[t].l;tr[t].l=k;tr[t].size=tr[k].size;update(k);k=t;}
19 void insert(int &k,int x)
20 {
21     if(k==0){len++;k=len;tr[k].size=tr[k].w=1;tr[k].v=x;tr[k].fix=rand();return;}
22     tr[k].size++;
23     if(tr[k].v==x)tr[k].w++;//每个结点顺便记录下与该节点相同值的数的个数
24     else if(x>tr[k].v){insert(tr[k].r,x);if(tr[tr[k].r].fix<tr[k].fix)lturn(k);}
25     else {insert(tr[k].l,x);if(tr[tr[k].l].fix<tr[k].fix)rturn(k);} 
26 }
27 void del(int &k,int x)
28 {
29     if(k==0)return; 
30     if(tr[k].v==x)
31     {
32         if(tr[k].w>1){tr[k].w--;tr[k].size--;return;}
33         if(tr[k].l*tr[k].r==0)k=tr[k].l+tr[k].r;//有一个儿子为空
34         else if(tr[tr[k].l].fix<tr[tr[k].r].fix) rturn(k),del(k,x);
35         else lturn(k),del(k,x);
36     }
37     else if(x>tr[k].v) tr[k].size--,del(tr[k].r,x);
38     else tr[k].size--,del(tr[k].l,x);
39 }
40 int rank(int k,int x)
41 {
42     if(k==0) return 0;
43     if(tr[k].v==x) return tr[tr[k].l].size+1;
44     else if(x>tr[k].v) return tr[tr[k].l].size+tr[k].w+rank(tr[k].r,x);
45     else return rank(tr[k].l,x);
46 }
47 int Findkth(int k,int x)
48 {
49     if(k==0)return 0;
50     if(x<=tr[tr[k].l].size) return Findkth(tr[k].l,x);
51     else if(x>tr[tr[k].l].size+tr[k].w) return Findkth(tr[k].r,x-tr[tr[k].l].size-tr[k].w);
52     else return tr[k].v;
53 }
54 void get_before(int k,int x)
55 {
56     if(k==0)return;
57     if(tr[k].v<x) ans=k;get_before(tr[k].r,x);
58     else get_before(tr[k].l,x);
59 }
60 void get_behind(int k,int x)
61 {
62     if(k==0)return;
63     if(tr[k].v>x) ans=k;get_behind(tr[k].l,x);
64     else get_behind(tr[k].r,x);
65 }
66 int main()
67 {
68     freopen("phs.in","r",stdin);
69     freopen("phs.out","w",stdout);
70     n=read();
71     int flag,x;
72     for(int i=1;i<=n;i++)
73     {
74         flag=read();  x=read();
75         switch(flag)
76         {
77             case 1:insert(root,x);break;
78             case 2:del(root,x);break;
79             case 3:printf("%d\n",rank(root,x));break;
80             case 4:printf("%d\n",Findkth(root,x));break;
81             case 5:ans=0;get_before(root,x);printf("%d\n",tr[ans].v);break;
82             case 6:ans=0;get_behind(root,x);printf("%d\n",tr[ans].v);break;
83         }
84     }
85     return 0;
86 }

 

【替罪羊树】

cojs上测试:运行时间 0.180 s     内存使用 2.63 MiB

  1 #include<iostream>
  2 #include<cstdio>
  3 #include<cstring>
  4 #include<cstdlib>
  5 #include<cmath>
  6 #include<ctime>
  7 #include<algorithm>
  8 using namespace std;
  9 #define INF 1000000000
 10 const double chty=0.75;  //平衡常数
 11 struct node{int son[2],f,size,v;}tr[100005];
 12 int n,len,root,top,stack[100005];
 13 char buf[1<<15],*fs,*ft;
 14 inline char getc() {return (fs==ft&&(ft=(fs=buf)+fread(buf,1,1<<15,stdin),fs==ft))?0:*fs++;}
 15 inline int read()
 16 {
 17     int x=0,f=1;  char ch=getc();
 18     while(!isdigit(ch))  {if(ch=='-')  f=-1;  ch=getc();}
 19     while(isdigit(ch))  {x=x*10+ch-'0';  ch=getc();}
 20     return x*f;
 21 }
 22 void init()
 23 {
 24     len=2;  root=1;
 25     tr[1].size=2;  tr[1].v=-INF;  tr[1].son[1]=2;
 26     tr[2].size=1;  tr[2].v=INF;   tr[2].f=1;
 27 }
 28 bool balance(int x) 
 29 {
 30     double p=tr[x].size*chty;
 31     return p>=(double)tr[tr[x].son[0]].size&&p>=(double)tr[tr[x].son[1]].size;
 32 }
 33 void dfs(int x)//中序遍历
 34 {
 35     if(!x)  return;
 36     dfs(tr[x].son[0]);
 37     stack[++top]=x;
 38     dfs(tr[x].son[1]);
 39 }
 40 int build(int l,int r)
 41 {
 42     if(l>r)  return 0;
 43     int mid=(l+r)/2,x=stack[mid];
 44     tr[tr[x].son[0]=build(l,mid-1)].f=x;
 45     tr[tr[x].son[1]=build(mid+1,r)].f=x;
 46     tr[x].size=tr[tr[x].son[0]].size+tr[tr[x].son[1]].size+1;
 47     return x;
 48 }
 49 void rebuild(int x)
 50 {
 51     top=0;  dfs(x);
 52     int fa=tr[x].f,which=(tr[fa].son[1]==x);
 53     int sonroot=build(1,top);
 54     tr[tr[fa].son[which]=sonroot].f=fa;
 55     if(x==root)  root=sonroot;
 56 }
 57 int find(int v)
 58 {
 59     int now=root;
 60     while(now)
 61     {
 62         if(v==tr[now].v)  return now;
 63         else now=tr[now].son[v>tr[now].v];
 64     }
 65 }
 66 void insert(int v)
 67 {
 68     int now=root,p=++len; 
 69     tr[p].v=v;  tr[p].size=1;//新开结点
 70     while(1)
 71     {
 72         tr[now].size++;
 73         int which=(v>=tr[now].v);//表示p在当前根的哪个子树内
 74         if(tr[now].son[which])  now=tr[now].son[which];  
 75         else {tr[tr[now].son[which]=p].f=now;  break;}
 76     }
 77     int id=0;
 78     for(int i=p;i;i=tr[i].f)  if(!balance(i))  id=i;//记录不平衡点
 79     if(id)  rebuild(id);//重构子树
 80 }
 81 void del(int x)
 82 {
 83     if(tr[x].son[0]&&tr[x].son[1])
 84     {
 85         int p=tr[x].son[0];
 86         while(tr[p].son[1])  p=tr[p].son[1];
 87         tr[x].v=tr[p].v;  x=p;
 88     }
 89     int Son=(tr[x].son[0])?tr[x].son[0]:tr[x].son[1],which=(tr[tr[x].f].son[1]==x);
 90     tr[tr[tr[x].f].son[which]=Son].f=tr[x].f;
 91     for(int i=tr[x].f;i;i=tr[i].f)  tr[i].size--;
 92     if(x==root)  root=Son;
 93 }
 94 int rank(int v)
 95 {
 96     int now=root,ans=0;
 97     while(now)
 98     {
 99         if(tr[now].v<v)  {ans+=tr[tr[now].son[0]].size+1;  now=tr[now].son[1];}
100         else now=tr[now].son[0];
101     }
102     return ans;
103 }
104 int kth(int x)
105 {
106     int now=root;
107     while(1)
108     {
109         if(tr[tr[now].son[0]].size==x-1)  return now;
110         else if(tr[tr[now].son[0]].size>=x)  now=tr[now].son[0];
111         else x-=tr[tr[now].son[0]].size+1,now=tr[now].son[1];
112     }
113     return now;
114 }
115 int before(int v)
116 {
117     int now=root,ans=-INF;
118     while(now)
119     {
120         if(tr[now].v<v)  ans=max(ans,tr[now].v),now=tr[now].son[1];
121         else now=tr[now].son[0];
122     }
123     return ans;
124 }
125 int after(int v)
126 {
127     int now=root,ans=INF;
128     while(now)
129     {
130         if(tr[now].v>v)  ans=min(ans,tr[now].v),now=tr[now].son[0];
131         else now=tr[now].son[1];
132     }
133     return ans;
134 }
135 int main()
136 {
137     freopen("phs.in","r",stdin);
138     freopen("phs.out","w",stdout);
139     init();
140     n=read();
141     for(int i=1;i<=n;i++)
142     {
143         int flag=read(),x=read();
144         if(flag==1)  insert(x);
145         if(flag==2)  del(find(x));
146         if(flag==3)  printf("%d\n",rank(x));
147         if(flag==4)  printf("%d\n",tr[kth(x+1)].v);
148         if(flag==5)  printf("%d\n",before(x));
149         if(flag==6)  printf("%d\n",after(x));
150     }
151     return 0;
152 }

不论从代码长度,还是实测时间上 ,显然Treap比较优

大力支持使用Treap

然而据说SBT比Treap的实测时间要优

有空学学 

 
 
posted @ 2016-10-08 13:20  chty  阅读(194)  评论(0编辑  收藏  举报