【bzoj3224】普通平衡树(splay板子)

来源:互联网 发布:嵌入式软件开发技术 编辑:程序博客网 时间:2024/05/20 02:55

Description

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

101 1064654 11 3177211 4609291 6449851 841851 898516 819681 4927375 493598

Sample Output

10646584185492737

I think

    代码参考(基本是二者的混合体qvq):
    史上最详尽的平衡树(splay)讲解与模板
    Splay伸展树学习笔记

    splay板子……
    稍微一提的是求前驱(后继),相当于新插入一个节点(顺便就旋至根节点啦),找根节点的左(右)子树中val最大(小)的节点,找到之后再删去该新建节点。
    对于删除节点,可利用find()函数(查询x数的排名)将目标点旋至根节点,通过判断其子树情况分类处理。这里具体写写两颗子树均不为空的删除操作。
    找到被删除节点x的左子树中val最大的节点y,并将其旋至x左子树根,由于y的val值大于左子树中任意其他节点,因此y一定没有右子树。那么将原x的右子树接至y的右子树,并将相关信息修改好就ok啦。

Code

#include<cstdio>#include<cstring>#include<algorithm>using namespace std;const int sm = 1e5+5;int u,n,m,sz,opt,rt;int f[sm],c[sm],cnt[sm],size[sm],ch[sm][2];char a;void read(int &x) {    x=0;a=getchar();u=1;    while(a>'9'||a<'0') {        if(a=='-')u=-1;a=getchar();    }    while(a>='0'&&a<='9')x=x*10+a-'0',a=getchar();    x*=u;}bool son(int p,int fa) {//判断p是fa的左子树还是右子树    return ch[fa][1]==p;}void clear(int p) {//删除点p的各项信息    f[p]=ch[p][0]=ch[p][1]=size[p]=cnt[p]=c[p]=0;}void newnode(int val,int fa) {//给fa创建一个新的子节点,记得在调用之后更新fa的ch    ++sz;f[sz]=fa;    ch[sz][0]=ch[sz][1]=0;    size[sz]=1;cnt[sz]=1;c[sz]=val;}void update(int x) {//更新以x为根的子树大小    if(x) {        size[x]=cnt[x];        if(ch[x][0])size[x]+=size[ch[x][0]];        if(ch[x][1])size[x]+=size[ch[x][1]];    }}void rotate(int x) {//把x旋至其父亲    int fa=f[x],gf=f[fa];    int a=son(x,fa),b=!a;    ch[fa][a]=ch[x][b];    if(ch[x][b])f[ch[x][b]]=fa;    ch[x][b]=fa,f[fa]=x;    f[x]=gf;    if(gf)ch[gf][son(fa,gf)]=x;    else rt=x;    update(fa);update(x);}void splay(int x,int p) {//将x旋至p的子节点    while(f[x]!=p) {        int fa=f[x],gf=f[fa];        if(p==gf)rotate(x);        else {            if(son(x,fa)^son(fa,gf))                rotate(x),rotate(x);            else rotate(fa),rotate(x);        }    }}void insert(int val) {//插入一个值为val的新节点    if(!rt){ newnode(val,0);rt=sz;return;}    int now=rt,fa=f[now];    while(now) {        if(c[now]==val) {            splay(now,0);cnt[now]++;return;//记得将节点旋至根        }        fa=now;        now=ch[fa][val>c[fa]];        if(!now) {            newnode(val,fa);            ch[fa][val>c[fa]]=sz;            update(fa);splay(sz,0);return;//记得将节点旋至根        }    }}int find(int val) {//查询值为val的点的排名    int ans=0,now=rt;    while(now) {        if(val<c[now])            now=ch[now][0];        else {            ans+=(ch[now][0]?size[ch[now][0]]:0);            if(val==c[now]) { splay(now,0);return ans+1;}            ans+=cnt[now];            now=ch[now][val>c[now]];        }    }}int findx(int p) {//查询排名为p的数    int ans=0,now=rt;    while(now) {        if(ch[now][0]&&p<=size[ch[now][0]])            now=ch[now][0];        else {            int tmp=(ch[now][0]?size[ch[now][0]]:0)+cnt[now];            if(p<=tmp)return c[now];            p-=tmp;            now=ch[now][1];        }    }}int pre() {//求前驱    int now=ch[rt][0];    while(ch[now][1])        now=ch[now][1];    return now;}int nxt() {//求后继    int now=ch[rt][1];    while(ch[now][0])        now=ch[now][0];    return now;}void del(int val) {//删除值为val的点    find(val);    if(cnt[rt]>1){--cnt[rt];return;}    if(!ch[rt][0]&&!ch[rt][1]){ clear(rt);return;}    else if(!ch[rt][0]) {        int t=rt;rt=ch[rt][1];f[rt]=0;clear(t);return;    }    else if(!ch[rt][1]) {        int t=rt;rt=ch[rt][0];f[rt]=0;clear(t);return;    }    int l=pre();    splay(l,rt);    f[ch[rt][1]]=l;    ch[l][1]=ch[rt][1];    f[l]=0;clear(rt);    rt=l;update(rt);}int main() {    read(n);    while(n--) {        read(opt);read(m);        if(opt==1)insert(m);        else if(opt==2)del(m);        else if(opt==3)printf("%d\n",find(m));        else if(opt==4)printf("%d\n",findx(m));        else {            insert(m);            if(opt==5)printf("%d\n",c[pre()]);            else printf("%d\n",c[nxt()]);            del(m);        }    }    return 0;}