问题描述:
您需要写一种数据结构(可参考题目标题),来维护一些数,其中需要提供以下操作:
- 插入x数
- 删除x数(若有多个相同的数,因只删除一个)
- 查询x数的排名(若有多个相同的数,因输出最小的排名)
- 查询排名为x的数
- 求x的前驱(前驱定义为小于x,且最大的数)
- 求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.每个数的数据范围:[-2e9,2e9]
思路:
模板题
对不平衡子树暴力重建
删点的时候找替罪羊
code:
#include<bits/stdc++.h>
using namespace std;
const int maxm=1e5+5;
const int inf=1e9;
const double alpha=0.75;
struct Node{
int val;
int fa;
int son[2];
int size;
}a[maxm];
int tot;
int root;
int cur[maxm],sum;//用来存中序遍历的序列
bool balance(int x){//判断是否平衡
return max(a[a[x].son[0]].size,a[a[x].son[1]].size)*1.0<=a[x].size*alpha;
}
int getlr(int x){
return a[a[x].fa].son[1]==x;
}
void dfs(int x){//中序遍历
if(!x)return ;
dfs(a[x].son[0]);
cur[++sum]=x;
dfs(a[x].son[1]);
}
int build(int l,int r){//重建BST子树
if(l>r)return 0;
int mid=(l+r)/2;
int x=cur[mid];
int lc=build(l,mid-1);
int rc=build(mid+1,r);
a[x].son[0]=lc,a[x].son[1]=rc;
a[lc].fa=a[rc].fa=x;
a[x].size=a[lc].size+a[rc].size+1;
return x;
}
void rebuild(int x){
sum=0;
dfs(x);
int fa=a[x].fa;
int pos=getlr(x);
int son=build(1,sum);//fa的新儿子,即x的新节点编号
a[son].fa=fa;
a[fa].son[pos]=son;
if(root==x)root=son;//如果重建的是整棵树,则son为新的根
}
void ffind_rebuild(int node,int x){//自上而下判断根到x路径上是否需要重建
if(!node)return ;
if(!balance(node)){
rebuild(node);
return ;
}
if(x<a[node].val){
ffind_rebuild(a[node].son[0],x);
}else{
ffind_rebuild(a[node].son[1],x);
}
}
void add(int x){
if(!root){
root=++tot;
a[root].val=x;
a[root].fa=a[root].son[0]=a[root].son[1]=0;
a[root].size=1;
return ;
}
int node=root;
while(1){
a[node].size++;
int fa=node;
int pos=(x>=a[node].val);//大于等于在右边
node=a[node].son[pos];
if(!node){
tot++;
a[tot].val=x;
a[tot].fa=fa;
a[tot].son[0]=a[tot].son[1]=0;
a[tot].size=1;
a[fa].son[pos]=tot;
break;
}
}
ffind_rebuild(root,x);
// int need=0;
// for(int i=tot;i;i=a[i].fa){
// if(!balance(i)){
// need=i;
// }
// }
// if(need)rebuild(need);
}
void del(int x){//删除编号为x的节点
if(a[x].son[0]&&a[x].son[1]){//r如果两边都不为空则寻找替罪羊
int node=a[x].son[0];//找左子树中最大的
while(a[node].son[1])node=a[node].son[1];
a[x].val=a[node].val;//找到之后替换信息,接下来删除替罪羊node
x=node;//x是需要删除的节点,如果找到替罪羊了则x=替罪羊
}
int son=a[x].son[a[x].son[0]==0];//son是替罪羊的唯一子儿子(可能为0)
int fa=a[x].fa;
int pos=getlr(x);
a[fa].son[pos]=son;
a[son].fa=fa;
for(int i=fa;i;i=a[i].fa){
a[i].size--;
}
if(root==x)root=son;//?
}
int getrank(int x){//求x的排名
int ans=0;//即求比x小的数的个数,结果+1就是x的排名
int node=root;
while(node){
if(x<=a[node].val){
node=a[node].son[0];
}else{
ans+=a[a[node].son[0]].size+1;
node=a[node].son[1];
}
}
return ans+1;
}
int getval(int x){//求排名为x的
int node=root;
while(1){
if(a[a[node].son[0]].size+1==x){//如果找到了
return a[node].val;
}
if(a[a[node].son[0]].size>=x){//左子树大于等于x则走左边
node=a[node].son[0];
}else{
x-=a[a[node].son[0]].size+1;
node=a[node].son[1];
}
}
}
int getfront(int x){//求x的前驱
int ans=-inf;
int node=root;
while(node){
if(a[node].val<x){
ans=max(ans,a[node].val);
node=a[node].son[1];
}else{
node=a[node].son[0];
}
}
return ans;
}
int getback(int x){//求x的后继
int ans=inf;
int node=root;
while(node){
if(a[node].val>x){
ans=min(ans,a[node].val);
node=a[node].son[0];
}else{
node=a[node].son[1];
}
}
return ans;
}
int getid(int x){//找到值为x的节点编号
int node=root;
while(node){
if(a[node].val==x)return node;
if(x<a[node].val){
node=a[node].son[0];
}else{
node=a[node].son[1];
}
}
return node;
}
signed main(){
int q;
scanf("%d",&q);
while(q--){
int d,x;
scanf("%d%d",&d,&x);
switch(d){
case 1:add(x);break;//插入x
case 2:del(getid(x));break;//删除x
case 3:printf("%d\n",getrank(x));break;//求x的排名
case 4:printf("%d\n",getval(x));break;//求排名为x的
case 5:printf("%d\n",getfront(x));break;//求x的前驱
case 6:printf("%d\n",getback(x));break;//求x的后继
}
}
return 0;
}
//https://vjudge.net/problem/HYSBZ-3224