zoukankan      html  css  js  c++  java
  • bzoj 3224: Tyvj 1728 普通平衡树

    3224: Tyvj 1728 普通平衡树

    Time Limit: 10 Sec  Memory Limit: 128 MB
    Submit: 17583  Solved: 7704
    [Submit][Status][Discuss]

    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

    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]
     
    /*
        这次敲明白了好多东西:
        学长之所以加一对哨兵节点(插入平衡树一个inf和-inf),是为了防止出现splay过程中根不存在的情况,出现在查询前驱和后驱时。替换的方法就是查询x的前驱时,先插入x,再查询,再删除。
        学长的代码为什么快呢,学长加入哨兵节点后,就省去了插入和删除的过程,所以跑的快。 
    */
    #include<cstdio>
    #include<iostream>
    #define maxn 100010
    using namespace std;
    int son[maxn][2],fa[maxn],val[maxn],cnt[maxn],sz[maxn],m,rt,size;
    void update(int x){
        sz[x]=sz[son[x][0]]+sz[son[x][1]]+cnt[x];
    }
    void rotate(int x){
        int y=fa[x],z=fa[fa[x]],l,r;
        if(son[y][0]==x)l=0;else l=1;r=l^1;
        son[y][l]=son[x][r];fa[son[x][r]]=y;
        son[x][r]=y;fa[y]=x;
        fa[x]=z;
        if(z)son[z][son[z][1]==y]=x;
        if(y==rt)rt=x;
        update(y);update(x);
    }
    void splay(int x){
        while(x!=rt){
            int y=fa[x],z=fa[fa[x]];
            if(y!=rt){
                if((son[y][0]==x)^(son[z][0]==y))rotate(x);
                else rotate(y);
            }
            rotate(x);
        }
    }
    void insert(int x){
        int k=rt,y=0;
        while(k&&val[k]!=x)y=k,k=son[k][x>val[k]];
        if(k)cnt[k]++;
        else{
            k=++size;cnt[size]=sz[size]=1;
            fa[size]=y;val[size]=x;
            if(y)son[y][x>val[y]]=k;
        }
        splay(k);
    }
    int find1(int x){//查找x的排名 
        int now=rt,ans=0;
        while(1){
            if(val[now]>x)now=son[now][0];
            else{
                if(son[now][0])ans+=sz[son[now][0]];
                if(val[now]==x){splay(now);return ans+1;}
                ans+=cnt[now];now=son[now][1];
            }
        }
    }
    int find2(int x){//查找排名为x的数 
        int k=rt;
        if(sz[k]<x)return 0;
        while(1){
            if(sz[son[k][0]]<x&&sz[son[k][0]]+cnt[k]>=x)return k;
            if(sz[son[k][0]]>=x)k=son[k][0];
            else x-=sz[son[k][0]]+cnt[k],k=son[k][1];
        }
    }
    int pre(int x){
        find1(x);
        if(val[rt]<x)return rt;
        int k=son[rt][0];
        while(son[k][1])k=son[k][1];
        return k;
    }
    int nxt(int x){
        find1(x);
        if(val[rt]>x)return rt;
        int k=son[rt][1];
        while(son[k][0])k=son[k][0];
        return k;
    }
    void clear(int x){
        son[x][0]=son[x][1]=fa[x]=sz[x]=cnt[x]=val[x]=0;
    }
    void del(int x){//错误比较集中 
        find1(x);
        int now=rt,k;
        if(cnt[rt]>1){cnt[rt]--,sz[rt]--;return;}
        if(!son[rt][0]||!son[rt][1]){
            int oldroot=rt;
            rt=son[rt][0]+son[rt][1];fa[rt]=0;
            clear(oldroot);return;
        }
        else{
            int leftbig=pre(val[rt]),oldroot=rt;
            splay(leftbig);
            son[rt][1]=son[oldroot][1];fa[son[oldroot][1]]=rt;
            clear(oldroot);
            update(rt);
        }
    }
    int main(){
        freopen("Cola.txt","r",stdin);
        scanf("%d",&m);
        for(int i=1;i<=m;i++){
            int opt,x;scanf("%d%d",&opt,&x);
            if(opt==1)insert(x);
            if(opt==2)del(x);
            if(opt==3)find1(x),printf("%d
    ",sz[son[rt][0]]+1);
            if(opt==4)printf("%d
    ",val[find2(x)]);
            if(opt==5)insert(x),printf("%d
    ",val[pre(x)]),del(x);
            if(opt==6)insert(x),printf("%d
    ",val[nxt(x)]),del(x);
        }
        return 0;
    }
    换了模板,以后用这个
    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #define maxn 1000000
    using namespace std;
    int ch[maxn][2],f[maxn],size[maxn],cnt[maxn],key[maxn];
    int sz,root;
    void update(int 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]];
        }
    }
    int get(int x){
        return ch[f[x]][1]==x;
    }
    void rotate(int x){
        int old=f[x],oldf=f[f[x]],whi=get(x);
        ch[old][whi]=ch[x][whi^1];f[ch[old][whi]]=old;
        if(oldf)ch[oldf][ch[oldf][1]==old]=x;f[x]=oldf;
        ch[x][whi^1]=old;f[old]=x;
        update(x);update(old);
    }
    void splay(int x){
        for(int fa;fa=f[x];rotate(x))
            if(f[fa])rotate(get(fa)==get(x)?fa:x);
        root=x;
    }
    void insert(int x){
        if(sz==0){
            sz++;root=sz;size[root]=cnt[root]=1;
            ch[root][0]=ch[root][1]=f[root]=0;key[root]=x;return;
        }
        int fa=0,now=root;
        while(1){
            if(key[now]==x){
                cnt[now]++;sz++;update(now);update(fa);splay(now);return;
            }
            fa=now;now=ch[now][key[now]<x];
            if(now==0){
                sz++;ch[sz][0]=ch[sz][1]=0;key[sz]=x;f[sz]=fa;size[sz]=cnt[sz]=1;
                ch[fa][key[fa]<x]=sz;update(fa);splay(sz);return;
            }
        }
    }
    int find(int x){
        int now=root,ans=0;
        while(1){
            if(key[now]>x)now=ch[now][0];
            else{
                if(ch[now][0])ans+=size[ch[now][0]];
                if(key[now]==x){splay(now);return ans+1;}
                ans+=cnt[now];now=ch[now][1];
            }
        }
    }
    int findx(int x){
        int now=root;
        while(1){
            if(ch[now][0]&&x<=size[ch[now][0]])now=ch[now][0];
            else {
                int tmp=(ch[now][0]?size[ch[now][0]]:0)+cnt[now];
                if(tmp>=x)return key[now];
                x-=tmp;now=ch[now][1];
            }
        }
    }
    int pre(){
        int now=ch[root][0];
        while(ch[now][1])now=ch[now][1];
        return now;
    }
    int nxt(){
        int now=ch[root][1];
        while(ch[now][0])now=ch[now][0];
        return now;
    }
    void clear(int x){
        cnt[x]=ch[x][0]=ch[x][1]=f[x]=size[x]=key[x]=0;
    }
    void del(int x){
        int where=find(x);
        if(cnt[root]>1){cnt[root]--;update(root);return;}
        if(!ch[root][0]&&!ch[root][1]){clear(root);root=0;return;}
        if(!ch[root][0]){
            int oldroot=root;f[ch[root][1]]=0;root=ch[oldroot][1];clear(oldroot);return;
        }
        if(!ch[root][1]){
            int oldroot=root;f[ch[root][0]]=0;root=ch[oldroot][0];clear(oldroot);return;
        }
        int leftbig=pre(),oldroot=root;
        splay(leftbig);
        ch[root][1]=ch[oldroot][1];f[ch[oldroot][1]]=root;
        clear(oldroot);
        update(root);
    }
    int main(){
        freopen("Cola.txt","r",stdin);
        int n,opt,x;
        scanf("%d",&n);
        for(int i=1;i<=n;i++){
            scanf("%d%d",&opt,&x);
            switch(opt){
                case 1:insert(x);break;
                case 2:del(x);break;
                case 3:printf("%d
    ",find(x));break;
                case 4:printf("%d
    ",findx(x));break;
                case 5:insert(x);printf("%d
    ",key[pre()]);del(x);break;
                case 6:insert(x);printf("%d
    ",key[nxt()]);del(x);break;
            }
        }
    }
    比较好看的代码
    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #define maxn 1000000
    using namespace std;
    int ch[maxn][2],f[maxn],size[maxn],cnt[maxn],key[maxn];
    int sz,root;
    void clear(int x){
        ch[x][0]=ch[x][1]=f[x]=size[x]=cnt[x]=key[x]=0;
    } 
    bool get(int x){
        return ch[f[x]][1]==x;
    }
    void update(int 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){
        int old=f[x],oldf=f[f[x]],whichx=get(x);
        ch[old][whichx]=ch[x][whichx^1];
        f[ch[old][whichx]]=old;
        ch[x][whichx^1]=old;f[old]=x;
        f[x]=oldf;
        if(oldf)ch[oldf][ch[oldf][1]==old]=x;
        update(old);update(x);
    }
    void splay(int x){
        for(int fa;fa=f[x];rotate(x))
            if(f[fa])rotate((get(x)==get(fa))?fa:x);
        root=x;
    }
    void insert(int x){//插入操作 
        if(root==0){//树为空 
            sz++;ch[sz][0]=ch[sz][1]=f[sz]=0;
            root=sz;size[sz]=cnt[sz]=1;key[sz]=x;return;
        }
        int now=root,fa=0;
        while(1){
            if(x==key[now]){//找到一个节点与要插入的数字相同 
                cnt[now]++;update(now);update(fa);splay(now);break;
            }
            fa=now;
            now=ch[now][key[now]<x];
            if(now==0){
                sz++;
                ch[sz][0]=ch[sz][1]=0;
                f[sz]=fa;
                size[sz]=cnt[sz]=1;
                ch[fa][key[fa]<x]=sz;
                key[sz]=x;
                update(fa);
                splay(sz);
                break;
            }
        }
    }
    int find(int x){//找x的排名 
        int now=root,ans=0;
        while(1){
            if(x<key[now])now=ch[now][0];//从左子树中找 
            else{
                ans+=(ch[now][0]?size[ch[now][0]]:0);
                if(x==key[now]){splay(now);return ans+1;}//要找的元素就在now位置 
                ans+=cnt[now];//还要向右儿子找 
                now=ch[now][1];
            }
        }
    }
    int findx(int x){//找排名为x的数字 
        int now=root;
        while(1){
            if(ch[now][0]&&x<=size[ch[now][0]])now=ch[now][0];//在左子树中 
            else{
                int tmp=(ch[now][0]?size[ch[now][0]]:0)+cnt[now];
                if(x<=tmp)return key[now];
                x-=tmp;now=ch[now][1];
            }
        }
    }
    int pre(){//前驱 
        int now=ch[root][0];
        while(ch[now][1])now=ch[now][1];
        return now;
    }
    int nxt(){//后继 
        int now=ch[root][1];
        while(ch[now][0])now=ch[now][0];
        return now;
    }
    void del(int x){
        int whatever=find(x);
        if(cnt[root]>1){cnt[root]--;update(root);return;}//根节点的权值大于1
        if(!ch[root][0]&&!ch[root][1]){clear(root);root=0;return;}//只有一个数字
        if(!ch[root][0]){//没有左儿子 
            int oldroot=root;root=ch[root][1];f[root]=0;clear(oldroot);return;
        } 
        else if(!ch[root][1]){//没有右儿子 
            int oldroot=root;root=ch[root][0];f[root]=0;clear(oldroot);return;
        }
        int leftbig=pre(),oldroot=root;
        splay(leftbig);
        ch[root][1]=ch[oldroot][1];
        f[ch[oldroot][1]]=root;
        clear(oldroot);
        update(root);
    }
    int main(){
        freopen("Cola.txt","r",stdin);
        int n,opt,x;
        scanf("%d",&n);
        for(int i=1;i<=n;i++){
            scanf("%d%d",&opt,&x);
            switch(opt){
                case 1:insert(x);break;
                case 2:del(x);break;
                case 3:printf("%d
    ",find(x));break;
                case 4:printf("%d
    ",findx(x));break;
                case 5:insert(x);printf("%d
    ",key[pre()]);del(x);break;
                case 6:insert(x);printf("%d
    ",key[nxt()]);del(x);break;
            }
        }
    }
    /*
        Treap
    */
    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<cstdlib>
    using namespace std;
    struct node{
        int l,r,v,rnd;
        int sz,w;//子树的大小  节点上数字的个数 
    }tr[100010];
    int n,size,root,ans;
    void update(int k){
        tr[k].sz=tr[tr[k].l].sz+tr[tr[k].r].sz+tr[k].w;
    }
    void lturn(int &k){
        int t=tr[k].r;tr[k].r=tr[t].l;tr[t].l=k;
        tr[t].sz=tr[k].sz;update(k);k=t;
    }
    void rturn(int &k){
        int t=tr[k].l;tr[k].l=tr[t].r;tr[t].r=k;
        tr[t].sz=tr[k].sz;update(k);k=t;
    }
    void insert(int &k,int x){
        if(k==0){
            size++;k=size;
            tr[k].sz=tr[k].w=1;tr[k].v=x;tr[k].rnd=rand();
            return;
        }
        tr[k].sz++;
        if(tr[k].v==x)tr[k].w++;
        else if(x>tr[k].v){
            insert(tr[k].r,x);
            if(tr[tr[k].r].rnd<tr[k].rnd)lturn(k);
        }
        else{
            insert(tr[k].l,x);
            if(tr[tr[k].l].rnd<tr[k].rnd)rturn(k);
        }
    }
    void del(int &k,int x){
        if(k==0)return;
        if(tr[k].v==x){
            if(tr[k].w>1){tr[k].w--;tr[k].sz--;return;}
            if(tr[k].l*tr[k].r==0)k=tr[k].l+tr[k].r;
            else if(tr[tr[k].l].rnd<tr[tr[k].r].rnd)rturn(k),del(k,x);
            else lturn(k),del(k,x);
        }
        else if(x>tr[k].v){tr[k].sz--;del(tr[k].r,x);}
        else{tr[k].sz--;del(tr[k].l,x);}
    }
    int query_rank(int k,int x){//查找x的排名 
        if(k==0)return 0;
        if(x==tr[k].v)return tr[tr[k].l].sz+1;
        if(x>tr[k].v)return tr[tr[k].l].sz+tr[k].w+query_rank(tr[k].r,x);
        return query_rank(tr[k].l,x);
    }
    int query_num(int k,int x){//查找排名为x的数字 
        if(k==0)return 0;
        if(x<=tr[tr[k].l].sz)return query_num(tr[k].l,x);
        else if(x>tr[k].w+tr[tr[k].l].sz)return query_num(tr[k].r,x-tr[k].w-tr[tr[k].l].sz);
        return tr[k].v;
    }
    void query_pro(int k,int x){//查找x的前驱 
        if(k==0)return;
        if(tr[k].v<x){ans=k;query_pro(tr[k].r,x);}
        else query_pro(tr[k].l,x);
    }
    void query_sub(int k,int x){
        if(k==0)return;
        if(tr[k].v>x){ans=k;query_sub(tr[k].l,x);}
        else query_sub(tr[k].r,x);
    }
    int main(){
        freopen("Cola.txt","r",stdin);
        scanf("%d",&n);
        int opt,x;
        while(n--){
            scanf("%d%d",&opt,&x);
            switch(opt){
                case 1:insert(root,x);break;
                case 2:del(root,x);break;
                case 3:printf("%d
    ",query_rank(root,x));break;
                case 4:printf("%d
    ",query_num(root,x));break;
                case 5:ans=0;query_pro(root,x);printf("%d
    ",tr[ans].v);break;
                case 6:ans=0;query_sub(root,x);printf("%d
    ",tr[ans].v);break;
            }
        }
        return 0;
    }

    一篇很棒的学Treap的论文

  • 相关阅读:
    C语言 realloc为什么要有返回值,realloc返回值具体解释/(解决随意长度字符串输入问题)。
    opencv中的vs框架中的Blob Tracking Tests的中文注释。
    Java实现 蓝桥杯VIP 算法提高 棋盘多项式
    Java实现 蓝桥杯VIP 算法提高 棋盘多项式
    Java实现 蓝桥杯VIP 算法提高 棋盘多项式
    Java实现 蓝桥杯VIP 算法提高 棋盘多项式
    Java实现 蓝桥杯VIP 算法提高 分苹果
    Java实现 蓝桥杯VIP 算法提高 分苹果
    Java实现 蓝桥杯VIP 算法提高 分苹果
    Java实现 蓝桥杯VIP 算法提高 分苹果
  • 原文地址:https://www.cnblogs.com/thmyl/p/8064223.html
Copyright © 2011-2022 走看看