bzoj 3224: Tyvj 1728 普通平衡树 (Splay模板)

题目:http://www.lydsy.com/JudgeOnline/problem.php?id=3224
题意:

您需要写一种数据结构(可参考题目标题),来维护一些数,其中需要提供以下操作:
1. 插入x数
2. 删除x数(若有多个相同的数,因只删除一个)
3. 查询x数的排名(若有多个相同的数,因输出最小的排名)
4. 查询排名为x的数
5. 求x的前驱(前驱定义为小于x,且最大的数)
6. 求x的后继(后继定义为大于x,且最小的数)

分析:

平衡树的入门题,可以当做一般平衡树操作的模板了~~
这题我是WA了好多次,我是用http://blog.csdn.net/crazy_ac/article/details/8034190这个大神的模板,不过总是WA,改了一些地方终于AC了,前几天可是耗费了我一天的功夫啊!,还是太菜了QAQ

代码:

#include<cstdio>
#include<cstdlib>
const int inf  = ~0u>>2;
#define L ch[x][0]
#define R ch[x][1]
#define KT (ch[ ch[rt][1] ][0])
const int maxn = 1e5+9;
int lim;
struct SplayTree {
    int sz[maxn];
    int ch[maxn][2];
    int pre[maxn];
    int rt,top;
    inline void up(int x) {
        sz[x]  = cnt[x]  + sz[ L ] + sz[ R ];
    }
    inline void Rotate(int x,int f) {
        int y=pre[x];
        ch[y][!f] = ch[x][f];
        pre[ ch[x][f] ] = y;
        pre[x] = pre[y];
        if(pre[x]) ch[ pre[y] ][ ch[pre[y]][1] == y ] =x;
        ch[x][f] = y;
        pre[y] = x;
        up(y);
    }
    inline void Splay(int x,int goal) { //将x旋转到goal的下面
        while(pre[x] != goal) {
            if(pre[pre[x]] == goal) Rotate(x , ch[pre[x]][0] == x);
            else   {
                int y=pre[x],z=pre[y];
                int f = (ch[z][0]==y);
                if(ch[y][f] == x) Rotate(x,!f),Rotate(x,f);
                else Rotate(y,f),Rotate(x,f);
            }
        }
        up(x);
        if(goal==0) rt=x;
    }
    inline void RTO(int k,int goal) { //将第k位数旋转到goal的下面
        int x=rt;
        while(sz[ L ] != k-1) {
            if(k < sz[ L ]+1) x=L;
            else {
                k-=(sz[ L ]+1);
                x = R;
            }
        }
        Splay(x,goal);
    }

    inline void Newnode(int &x,int c,int f) {
        x=++top;
        L = R = 0;
        pre[x] = f;
        sz[x]=1;
        cnt[x]=1;
        val[x] = c;
    }
    inline void init() {
        ch[0][0]=ch[0][1]=pre[0]=sz[0]=0;
        rt=top=0;
        cnt[0]=0;
    }
    inline void Insert(int &x,int key,int f) {
        if(!x) {
            Newnode(x,key,f);
            Splay(x,0);//注意插入完成后splay
            return ;
        }
        if(key==val[x]) {
            cnt[x]++;
            sz[x]++;
            Splay(x,0);//注意插入完成后splay
            return ;
        } else if(key<val[x]) {
            Insert(L,key,x);
        } else {
            Insert(R,key,x);
        }
        up(x);
    }
    void Del_root() { //删除根节点
        int t=rt;
        if(ch[rt][1]) {
            rt=ch[rt][1];
            RTO(1,0);
            ch[rt][0]=ch[t][0];
            if(ch[rt][0]) pre[ch[rt][0]]=rt;
        } else rt=ch[rt][0];
        pre[rt]=0;
        up(rt);
    }
    void findpre(int x,int key,int &ans) { //找前驱节点
        ans=-inf;
        while(x) {
            if(val[x]<key) {
                if(val[x]>ans)ans=val[x];
                x=R;
            } else x=L;
        }
    }
    void findsucc(int x,int key,int &ans) { //找后继节点
        ans=inf;
        while(x) {
            if(val[x]>key) {
                if(val[x]<ans)ans=val[x];
                //  ans=min(ans,val[x]);
                x=L;
            } else x=R;
        }
    }
    inline int find_kth(int x,int k) { //第k小的数
        if(k<sz[L]+1) {
            return find_kth(L,k);
        } else if(k > sz[ L ] + cnt[x] )
            return find_kth(R,k-sz[L]-cnt[x]);
        else {
            Splay(x,0);
            return val[x];
        }
    }
    int find(int key) {
        int x=rt;
        while(x&&val[x]!=key)
            x=ch[x][key>val[x]];
        if(x)Splay(x,0); //0是没找到
        return x;
    }
    int find(int x,int key) {
        //if(!x) return 0;
        while(x&&val[x]!=key)x=ch[x][key>val[x]];
        return x;
    }

    int rank(int key) {
        int x = find(key);
        //Splay(x,rt);
        return sz[ch[rt][0]]+1;
    }
    //确定key的排名
    int get_rank(int x) {
        int *key=val;
        int r=rt,temp=0;

        while(ch[r][key[r]<=x]) {
            if(key[r]==x) break;
            if(key[r]<=x) temp+=sz[r]-sz[ch[r][1]];
            r=ch[r][key[r]<=x];
        }
        return sz[ch[r][0]]+1+temp;
    }
    int getrank(int x,int key,int cur) { //cur:当前已知比要求元素(key)小的数的个数
        if(key == val[x])
            return sz[L] + cur + 1;
        else if(key < val[x])
            return getrank(L,key,cur);
        else
            return getrank(R,key,cur+sz[L]+cnt[rt]);
    }

    void del(int &x,int f) { //删除小于lim的所有的数所在的节点
        if(!x) return ;
        if(val[x]>=lim) {
            del(L,x);
        } else {
            x=R;
            pre[x]=f;
            if(f==0)  rt=x;
            del(x,f);
        }
        if(x)  up(x);
    }

    void Delete(int key) {
        int node=find(rt,key);
        Splay(node,0);
        cnt[rt]--;
        if(cnt[rt]<=0)Del_root();
    }

    void solve(int n) {
        int x,op,ans,tot=0;
        for(int i=0; i<n; i++) {
            scanf("%d%d",&op,&x);          
            if(op==1) {
                Insert(rt,x,0);
                continue;
            } else if(op==2) {
                Delete(x);
                continue;
            } else if(op==3) {
                ans=rank(x);              
            } else if(op==4) {
                ans=find_kth(rt,x);
            } else if(op==5) {
                findpre(rt,x,ans);
            } else if(op==6) {
                findsucc(rt,x,ans);
            }
            printf("%d\n",ans);
        }
    }
    int cnt[maxn];
    int val[maxn];
    int lim;
} spt;

int main() {
    int n;
    while(~scanf("%d",&n)) {
        spt.init();
        spt.solve(n);
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值