平衡树模板
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的实测时间要优
有空学学