洛谷 P3369 【模板】普通平衡树

洛谷 P3369 【模板】普通平衡树

洛谷传送门

题目描述

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

  1. 插入 xx
  2. 删除 xx 数(若有多个相同的数,因只删除一个)
  3. 查询 xx 数的排名(排名定义为比当前数小的数的个数 +1+1 )
  4. 查询排名为 xx 的数
  5. 求 xx 的前驱(前驱定义为小于 xx,且最大的数)
  6. 求 xx 的后继(后继定义为大于 xx,且最小的数)

输入格式

第一行为 nn,表示操作的个数,下面 nn 行每行有两个数 ext{opt}opt 和 xx, ext{opt}opt 表示操作的序号( 1 leq ext{opt} leq 61≤opt≤6 )

输出格式

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

说明/提示

【数据范围】
对于 100%100% 的数据,1le n le 10^51≤n≤105,|x| le 10^7∣x∣≤107

来源:Tyvj1728 原名:普通平衡树

在此鸣谢


题解:

题如其名。

平衡树不会的请走这边:

Treap详解

Splay详解

蒟蒻只学了两种平衡树qwq...蒟蒻太菜了。

最后还是用SplayAC的:

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn=1e5+10;
int n;
int tot,root;
int val[maxn],size[maxn],cnt[maxn],fa[maxn],ch[maxn][2];
void maintain(int x)
{
    size[x]=cnt[x]+size[ch[x][0]]+size[ch[x][1]];
}
int find(int x)
{
    int pos=root;
    while(val[pos]!=x)
        pos=ch[pos][x>val[pos]];
    return pos;
}
int get(int x)
{
    int f=fa[x];
    return ch[f][1]==x;
}
void rotate(int x)
{
    int y=fa[x],z=fa[y];
    int k=get(x);//k表示x是y的什么儿子
    ch[y][k]=ch[x][k^1],fa[ch[y][k]]=y;
    ch[x][k^1]=y,fa[y]=x,fa[x]=z;
    if(z)
        ch[z][ch[z][1]==y]=x;
    maintain(y),maintain(x);
}
void splay(int x,int &goal)
{
    int f=fa[goal];
    while(fa[x]!=f)
    {
        if(fa[fa[x]]!=f)
            rotate(get(x)==get(fa[x])?fa[x]:x);
        rotate(x);
    }
    goal=x;
}
void insert(int x)
{
    if(!root)
    {
        ++tot;
        root=tot;
        val[root]=x;
        cnt[root]=1;
        maintain(root);
        return;
    }
    int pos,f;
    pos=f=root;
    while(pos && val[pos]!=x)
        f=pos,pos=ch[pos][x>val[pos]];
    if(!pos)
    {
        ++tot;
        cnt[tot]=1;
        val[tot]=x;
        fa[tot]=f;
        ch[f][x>val[f]]=tot;
        maintain(tot);
        splay(tot,root);
        return;
    }
    ++cnt[pos];
    maintain(pos);
    splay(pos,root);
}
void del(int x)
{
    int pos=find(x);
    splay(pos,root);
    if(cnt[root]>1)
    {
        cnt[root]--;
        maintain(root);
        return;
    }
    if((!ch[root][0])&&(!ch[root][1]))
        root=0;
    else if(!ch[root][0])
        root=ch[root][1],fa[root]=0;
    else if(!ch[root][1])
        root=ch[root][0],fa[root]=0;
    else
    {
        pos=ch[root][0];
        while(ch[pos][1])
            pos=ch[pos][1];
        splay(pos,ch[root][0]);
        ch[pos][1]=ch[root][1];
        fa[ch[root][1]]=pos,fa[pos]=0;
        maintain(pos);
        root=pos;
    }
}
int rank(int x)
{
    int pos=find(x);
    splay(pos,root);
    return size[ch[root][0]]+1;
}
int kth(int x)
{
    int pos=root;
    while(1)
    {
        if(x<=size[ch[pos][0]])
            pos=ch[pos][0];
        else 
        {
            x-=(size[ch[pos][0]]+cnt[pos]);
            if(x<=0)
            {
                splay(pos,root);
                return val[pos];
            }
            pos=ch[pos][1];
        }
    }
}
int pre(int x)
{
    int ans;
    int pos=root;
    while(pos)
    {
        if(x>val[pos])
        {
            ans=val[pos];
            pos=ch[pos][1];
        }
        else
            pos=ch[pos][0];
    }
    return ans;
}
int nxt(int x)
{
    int ans;
    int pos=root;
    while(pos)
    {
        if(x<val[pos])
        {
            ans=val[pos];
            pos=ch[pos][0];
        }
        else
            pos=ch[pos][1];
    }
    return ans;
}
int main()
{
    scanf("%d",&n);
    while(n--)
    {
        int opt,x;
        scanf("%d%d",&opt,&x);
        if(opt==1)
            insert(x);
        if(opt==2)
            del(x);
        if(opt==3)
            printf("%d
",rank(x));
        if(opt==4)
            printf("%d
",kth(x));
        if(opt==5)
            printf("%d
",pre(x));
        if(opt==6)
            printf("%d
",nxt(x));
    }
    return 0;
}
原文地址:https://www.cnblogs.com/fusiwei/p/13391495.html