【模板】普通平衡树
题目链接
题目描述
您需要写一种数据结构(可参考题目标题),来维护一些数,其中需要提供以下操作:
- 插入 xx 数
- 删除 xx 数(若有多个相同的数,因只删除一个)
- 查询 xx 数的排名(排名定义为比当前数小的数的个数 +1+1 。若有多个相同的数,因输出最小的排名)
- 查询排名为 xx 的数
- 求 xx 的前驱(前驱定义为小于 xx ,且最大的数)
- 求 xx 的后继(后继定义为大于 xx ,且最小的数)
输入输出格式
输入格式:
第一行为 nn ,表示操作的个数,下面 nn 行每行有两个数 optopt 和 xx , optopt 表示操作的序号( 1 leq opt leq 61≤opt≤6 )
输出格式:
对于操作 3,4,5,63,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.每个数的数据范围: ([-10^7,10^7])
替罪羊树
学习总结
#include<bits/stdc++.h>
using namespace std;
int read()
{
int x=0,w=1;char ch=getchar();
while(ch>'9'||ch<'0') {if(ch=='-')w=-1;ch=getchar();}
while(ch>='0'&&ch<='9') x=(x<<3)+(x<<1)+ch-'0',ch=getchar();
return x*w;
}
double alpha=0.75;
int n,x,opt,cnt,root,need,top;
int s[100010];
struct node{
int son[2],v,die,s;
}t[100010];
bool exist(int k){return (t[k].die^1);}
bool bad(int k)
{
int k1=t[k].son[0],k2=t[k].son[1];
return (double)max(t[k1].s,t[k2].s)>=(double)t[k].s*alpha;
}
void dfs(int k)
{
if(!k) return;
dfs(t[k].son[0]);if(!t[k].die)s[++top]=k;dfs(t[k].son[1]);
}
void build(int &k,int l,int r)
{
if(l>r)return;int mid=(l+r)/2;k=s[mid];
if(l==r)
{
t[k].s=1;t[k].son[0]=t[k].son[1]=t[k].die=0;return;
}
if(l<mid) build(t[k].son[0],l,mid-1);else t[k].son[0]=0;
if(r>mid) build(t[k].son[1],mid+1,r);else t[k].son[1]=0;
t[k].s=t[t[k].son[0]].s+t[t[k].son[1]].s+1;return;
}
void rebuild(int &k)
{
top=0;dfs(k);if(top)build(k,1,top);
}
void insert(int &k,int v)
{
if(!k)
{
k=++cnt;t[k].v=v;t[k].s=1;return;
}
if(v<=t[k].v) insert(t[k].son[0],v);
else insert(t[k].son[1],v);
int k1=t[k].son[0],k2=t[k].son[1];
t[k].s=t[k1].s+t[k2].s+exist(k);
if(!bad(k))
{
if(need)
{
if(need==t[k].son[0]) rebuild(t[k].son[0]);
else rebuild(t[k].son[1]);
}
need=0;
}
else need=k;
}
void delet(int k,int v)
{
if(!k) return;
int k1=t[k].son[0],k2=t[k].son[1];
if(!t[k].die&&t[k1].s+1==v){t[k].die=1;t[k].s--;return;}
if(t[k1].s>=v) delet(k1,v);
else delet(k2,v-t[k1].s-exist(k));
t[k].s=t[k1].s+t[k2].s+exist(k);
if(!bad(k))
{
if(need)
{
if(need==t[k].son[0]) rebuild(t[k].son[0]);
else rebuild(t[k].son[1]);
}
need=0;
}
else need=k;
}
int getrank(int k,int v)
{
if(!k) return 0;
int k1=t[k].son[0],k2=t[k].son[1];
if(t[k].v<v) return t[k1].s+exist(k)+getrank(k2,v);
return getrank(k1,v);
}
int kth(int k,int v)
{
if(!k) return 0;
int k1=t[k].son[0],k2=t[k].son[1];
if(!t[k].die&&t[k1].s+1==v) return t[k].v;
if(t[k1].s>=v) return kth(k1,v);
return kth(k2,v-t[k1].s-exist(k));
}
int main()
{
n=read();
for(int i=1;i<=n;i++)
{
opt=read();x=read();
if(opt==1){insert(root,x);if(need)rebuild(root),need=0;}
if(opt==2)
{
int d=getrank(root,x)+1;
delet(root,d);
if(need)rebuild(root),need=0;
}
if(opt==3) printf("%d
",getrank(root,x)+1);
if(opt==4) printf("%d
",kth(root,x));
if(opt==5) printf("%d
",kth(root,getrank(root,x)));
if(opt==6) printf("%d
",kth(root,getrank(root,x+1)+1));
}
}
Splay
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
int read()
{
int x=0,w=1;char ch=getchar();
while(ch>'9'||ch<'0') {if(ch=='-')w=-1;ch=getchar();}
while(ch>='0'&&ch<='9') x=(x<<3)+(x<<1)+ch-'0',ch=getchar();
return x*w;
}
int root,cnt,inf=2100000000;
struct node{
int fa,son[2],size,cnt,v;
}tree[100010];
void push_up(int);
void splay(int,int);
bool get(int);
void rotate(int);
void insert(int);
void delet(int);
int getrank(int);
int getsum(int);
int find(int);
int kth(int,int);
int main()
{
int n=read(),opt,x;
insert(inf);insert(-inf);
for(int i=1;i<=n;i++)
{
opt=read();x=read();
if(opt==1) insert(x);
else if(opt==2) delet(x);
else if(opt==3) printf("%d
",getrank(x));
else if(opt==4) printf("%d
",getsum(x+1));
else if(opt==5) printf("%d
",tree[kth(x,0)].v);
else if(opt==6) printf("%d
",tree[kth(x,1)].v);
}
}
void push_up(int k)
{
tree[k].size=tree[tree[k].son[0]].size+tree[tree[k].son[1]].size+tree[k].cnt;
}
bool get(int k)
{
return k==tree[tree[k].fa].son[1];
}
void rotate(int k)
{
int fa=tree[k].fa,gfa=tree[fa].fa,d1=get(k),d2=get(fa);
tree[fa].son[d1]=tree[k].son[d1^1];tree[tree[k].son[d1^1]].fa=fa;
tree[k].son[d1^1]=fa;tree[fa].fa=k;
tree[gfa].son[d2]=k;tree[k].fa=gfa;
push_up(fa);push_up(k);
}
void splay(int k,int goal)
{
while(tree[k].fa!=goal)
{
int fa=tree[k].fa,gfa=tree[fa].fa,d1=get(k),d2=get(fa);
if(gfa!=goal)
{
if(d1==d2) rotate(fa);
else rotate(k);
}
rotate(k);
}
if(goal==0) root=k;
}
void insert(int k)
{
int now=root,fa=0;
while(tree[now].v!=k&&now)
fa=now,now=tree[now].son[k>tree[now].v];
if(now)
tree[now].cnt++;
else
{
now=++cnt;
if(fa) tree[fa].son[k>tree[fa].v]=now;
tree[now].v=k;
tree[now].fa=fa;
tree[now].cnt=1;
tree[now].size=1;
}
splay(now,0);
}
void delet(int k)
{
int last=kth(k,0),next=kth(k,1);
splay(last,0);splay(next,last);
if(tree[tree[next].son[0]].cnt>1)
{
tree[tree[next].son[0]].cnt--;
splay(tree[next].son[0],0);
}
else tree[next].son[0]=0;
}
int find(int k)
{
int now=root;
while(tree[now].v!=k&&tree[now].son[tree[now].v<k])
now=tree[now].son[tree[now].v<k];
return now;
}
int getrank(int k)
{
splay(find(k),0);
return tree[tree[root].son[0]].size;
}
int getsum(int k)
{
int now=root;
while(1)
{
if(k>tree[tree[now].son[0]].size&&k<=tree[tree[now].son[0]].size+tree[now].cnt) return tree[now].v;
else if(k>tree[tree[now].son[0]].size+tree[now].cnt) k-=tree[tree[now].son[0]].size+tree[now].cnt,now=tree[now].son[1];
else now=tree[now].son[0];
}
}
int kth(int k,int judge)
{
int x=find(k);
splay(x,0);
if(judge==0&&k>tree[root].v) return root;
if(judge==1&&k<tree[root].v) return root;
int now=tree[root].son[judge];
while(tree[now].son[judge^1])
now=tree[now].son[judge^1];
return now;
}