bzoj3224 普通平衡树 (替罪羊树)

问题描述:

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

  1. 插入x数
  2. 删除x数(若有多个相同的数,因只删除一个)
  3. 查询x数的排名(若有多个相同的数,因输出最小的排名)
  4. 查询排名为x的数
  5. 求x的前驱(前驱定义为小于x,且最大的数)
  6. 求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
发布了364 篇原创文章 · 获赞 26 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/weixin_44178736/article/details/103377294