HIT暑期集训 平衡树

贴几篇网上找的splay入门博客

https://www.cnblogs.com/cjyyb/p/7499020.html

https://www.cnblogs.com/santiego/p/10011592.html

B    HihoCoder 1333

C    HihoCoder 1034

D    HDU 4680

E    计蒜客 T2009

G    LibreOJ 104

模板题,参考了网上的treap模板(我不会写啊)

#include<cstdio>
#include<algorithm>
#define maxn 100010
#define inf 200000000
using namespace std;
struct node
{
    int siz,num,va,pri;
}e[maxn];
int son[maxn][2],cnt=0,rt=0;
void pushup(int k)
{
    e[k].siz=e[son[k][0]].siz+e[son[k][1]].siz+e[k].num;
}
void rotate(int &p,int d)//0左旋1右旋 
{
    int k=son[p][d^1];//k为p的d^1儿子 
    son[p][d^1]=son[k][d];
    son[k][d]=p;//k的d儿子变为p
    pushup(p);
    pushup(k); 
    p=k;
} 
void ins(int &p,int x)//k为当前节点,x为要插入的数字 
{
    if (!p)//空节点 
    {
        p=++cnt;//赋予节点编号
        e[p].siz=1;
        e[p].num=1;
        e[p].va=x;
        e[p].pri=rand(); 
        return; 
    }
    if (e[p].va==x)
    {
        e[p].siz++;
        e[p].num++;
        return;
    }
    int d;
    if (x>e[p].va) d=1;
    else d=0;
    ins(son[p][d],x);
    if (e[p].pri<e[son[p][d]].pri) rotate(p,d^1);//维护pri大根堆 
    pushup(p);
}
void del(int &p,int x)
{
    if (!p) return;
    if (x<e[p].va) del(son[p][0],x);
    else if (x>e[p].va) del(son[p][1],x);
    else 
    {
        if (!son[p][0] && !son[p][1])//叶子节点,直接删除 
        {
            e[p].num--;
            e[p].siz--;
            if (e[p].num==0) p=0;
        }
        else if (son[p][0] && !son[p][1])//只有一个儿子的情况,把儿子转上来,到子树里解决 
        {
            rotate(p,1);
            del(son[p][1],x);
        }
        else if (!son[p][0] && son[p][1])
        {
            rotate(p,0);
            del(son[p][0],x);
        }
        else if (son[p][0] && son[p][1])//把较大的儿子转上来,去另一个子树里解决 
        {
            int d;
            if (e[son[p][0]].pri>e[son[p][1]].pri) d=1;
            else d=0;
            rotate(p,d);
            del(son[p][d],x);
        }
    }
    pushup(p);
}
int rk(int p,int x)
{
    if (!p) return 0;
    if (e[p].va==x) return e[son[p][0]].siz+1;
    if (e[p].va>x) return rk(son[p][0],x);
    //x在左子树中 
    if (e[p].va<x) return e[son[p][0]].siz+e[p].num+rk(son[p][1],x);
    //x在右子树中,排名先加上左子树大小和当前位置次数 
}
int find(int p,int x)
{
    if (!p) return 0;
    if (e[son[p][0]].siz>=x) return find(son[p][0],x);
    //rk小于左子树大小,去左子树中找答案 
    else if (e[son[p][0]].siz+e[p].num<x) return find(son[p][1],x-e[son[p][0]].siz-e[p].num);
    //rk大于左子树大小和当前位置次数的和,去右子树中找答案 
    else return e[p].va;
}
int pre(int p,int x)
{
    if (!p) return -inf;
    if (e[p].va>=x) return pre(son[p][0],x);
    //当前值大于等于x,去左子树里找先驱 
    else return max(e[p].va,pre(son[p][1],x));
    //当前值小于x,去右子树里找先驱,并与当前值比较得出答案 
}
int suc(int p,int x)
{
    if (!p) return inf;
    if (e[p].va<=x) return suc(son[p][1],x);
    else return min(e[p].va,suc(son[p][0],x));
}
int main()
{
    int n,op,x;
    scanf("%d",&n);
    while (n--)
    {
        scanf("%d%d",&op,&x);
        if (op==1) ins(rt,x);
        else if (op==2) del(rt,x);
        else if (op==3) printf("%d\n",rk(rt,x)); 
        else if (op==4) printf("%d\n",find(rt,x)); 
        else if (op==5) printf("%d\n",pre(rt,x)); 
        else if (op==6) printf("%d\n",suc(rt,x)); 
    }
    return 0;
}

 

posted @ 2020-08-06 17:06  lsy_kk  阅读(106)  评论(0)    收藏  举报