• BZOJ 3224 普通平衡树


    AC通道:http://www.lydsy.com/JudgeOnline/problem.php?id=3224

    平衡树的模板题,Splay操作可以让平均复杂度降到log(n)。

    插入,即二叉搜索树的插入

    删除,先Splay要删除的节点,然后将左右子树合并

    前驱后继都可以直接用二叉搜索树的功能。

    查询数的排名的时候,只需要Splay这个数,然后求左子树的节点个数就好了。

    查询排名第k的时候,需要发挥神奇的记录存在这个节点下的子树上的节点个数的属性,然后利用搜索二叉树的方法,进行二分搜索,判断位置。

    我的代码很长...但是我觉得还是蛮好看的恩...因为没有看过别人的模板...

    数据结构题真的调好久啊,好久啊

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    
    using namespace std;
    
    const int maxn=100010;
    
    inline int in(){
        int x=0,flag=1;char ch=getchar();
        while((ch>'9' || ch<'0') && ch!='-') ch=getchar();
        if(ch=='-') flag=-1,ch=getchar();
        while(ch>='0' && ch<='9') x=x*10+ch-'0',ch=getchar();
        return x*flag;/*忘记乘flag*/
    }
    
    int cnt;
    
    struct Node{
        int data,sum,cot;
        int l,r,f;
    }s[maxn];
    
    inline void updata(int a){
        s[a].sum=s[s[a].l].sum+s[s[a].r].sum+s[a].cot;
    }
    
    inline void up_updata(int a){
        while(a){
            s[a].sum=s[s[a].l].sum+s[s[a].r].sum+s[a].cot;
            a=s[a].f;
        }
    }
    
    void print(int Root){
        if(!Root) return;
        print(s[Root].l);
        for(int i=1;i<=s[Root].cot;i++)
            printf("%d ",s[Root].data);
        print(s[Root].r);
    }
    
    void zig(int x){
        int y=s[x].f;
        
        s[y].l=s[x].r;
        if(s[x].r) s[s[x].r].f=y;
        
        s[x].f=s[y].f;
        if(s[y].f){
            if(y==s[s[y].f].l) s[s[y].f].l=x;
            else s[s[y].f].r=x;
        }
        
        s[y].f=x,s[x].r=y;
        updata(y),updata(x);/*这里顺序反过一次*/
    }
    
    void zag(int x){
        int y=s[x].f;
        
        s[y].r=s[x].l;
        if(s[x].l) s[s[x].l].f=y;
        
        s[x].f=s[y].f;
        if(s[y].f){
            if(y==s[s[y].f].l) s[s[y].f].l=x;
            else s[s[y].f].r=x;
        }
        
        s[y].f=x,s[x].l=y;
        updata(y),updata(x);
    }
    
    void Splay(int x,int &Root){
        int y;
        
        while(s[x].f){
            y=s[x].f;
            if(!s[y].f){
                if(x==s[y].l) zig(x);
                else zag(x);
                break;
            }
            if(x==s[y].l){
                if(y==s[s[y].f].l) zig(y),zig(x);
                else zig(x),zag(x);
            }
            else{
                if(y==s[s[y].f].r) zag(y),zag(x);
                else zag(x),zig(x);
            }
        }
        
        Root=x;
    }
    
    int Find(int x,int &Root){
        int p=Root;
        while(p){
            if(s[p].data==x) break;
            else if(s[p].data>x) p=s[p].l;
            else p=s[p].r;
        }
        if(!p) return 0;
        Splay(p,Root);
        return p;
    }
    
    void Insert(int x,int &Root){
        int p=Root;
        if(!p){
            Root=++cnt,s[cnt].f=0,s[cnt].data=x,s[cnt].cot=s[cnt].sum=1;
            return;
        }
        while(p){
            if(s[p].data==x){
                s[p].cot++;up_updata(p)/*这里打成cnt*/;break;
            }
            else if(s[p].data>x){
                if(s[p].l)
                    p=s[p].l;
                else{
                    s[p].l=++cnt,s[cnt].f=p,s[cnt].data=x,s[cnt].cot=1,up_updata(cnt);
                    break;
                }
            }
            else{
                if(s[p].r)
                    p=s[p].r;
                else{
                    s[p].r=++cnt,s[cnt].f=p,s[cnt].data=x,s[cnt].cot=1,up_updata(cnt);
                    break;
                }
            }
        }
    }
    
    int find_max(int &Root){
        int p=Root;
        while(s[p].r) p=s[p].r;
        Splay(p,Root);
        return p;
    }
    
    
    int find_min(int &Root){
        int p=Root;
        while(s[p].l) p=s[p].l;
        Splay(p,Root);
        return p;
    }
    
    int pre(int x,int &Root){
        int p=Root,last=p;
        while(p)
            if(s[p].data>=x) p=s[p].l;
            else
                last=p,p=s[p].r;
        return last;
    }
    
    int las(int x,int &Root){
        int p=Root,last=p;
        while(p)
            if(s[p].data<=x) p=s[p].r;
            else
                last=p,p=s[p].l;
        return last;
    }
    
    int Union(int &Root1,int Root2){
        if(!Root1) {s[Root2].f=0;return Root2;}
        if(!Root2) {s[Root1].f=0;return Root1;}
        int p=find_max(Root1);
        s[p].r=Root2;
        s[Root2].f=p;
        updata(p);
        return p;
    }
    
    void Delete(int x,int &Root){
        int p=Find(x,Root);
        if(s[p].cot==1)
            Root=Union(s[p].l,s[p].r);
        else
            s[p].cot--,s[p].sum--;
    }
    
    int get_rank(int x,int &Root){
        int p=Find(x,Root);
        return s[s[p].l].sum;
    }
    
    int get_num(int k,int Root){
        int p=Root;
        while(p){
            if(k<=s[s[p].l].sum) p=s[p].l;
            else{
                k-=s[s[p].l].sum;
                if(k<=s[p].cot)
                    return s[p].data;
                else
                    k-=s[p].cot,p=s[p].r;
            }
        }
        return 0;
    }
    
    int main(){
    #ifndef ONLINE_JUDGE
        freopen("3224.in","r",stdin);
        freopen("3224.out","w",stdout);
    #endif
    
        int kase=in(),ord,x,Root=0;
    
        while(kase--){
            ord=in();x=in();
            if(ord==1)
                Insert(x,Root);
            else if(ord==2)
                Delete(x,Root);
            else if(ord==3)
                printf("%d
    ",get_rank(x,Root)+1);
            else if(ord==4)
                printf("%d
    ",get_num(x,Root));
            else if(ord==5)
                printf("%d
    ",s[pre(x,Root)].data);
            else
                printf("%d
    ",s[las(x,Root)].data);
            //print(Root);putchar('
    ');
        }
    
        return 0;
    }
    View Code

    附送这题的make_data,虽然做的有点丑吧...但是应该不会造出错误的数据...

    #include<cstdio>
    #include<cstring>
    #include<cstdlib>
    #include<ctime>
    #include<cmath>
    #include<algorithm>
    
    using namespace std;
    
    int rec[10010];
    
    bool cmp(const int a,const int b){
        //return a<b;
        //return cos(a)<sin(b);
        return rand()%10<rand()%10;
    }
    
    int main(){
        freopen("3224.in","w",stdout);
        
        srand(time(0));
        
        int cnt=0,t=rand()%1+100000;
        
        printf("%d
    ",t);
        
        for(int i=1;i<=t;i++){
            int ord=rand()%6+1,x=rand()%100000+1;
            if(cnt<=1) ord=1;
            if(ord==1){
                rec[++cnt]=x;
                printf("1 %d
    ",x);
            }
            else if(ord==2){
                printf("2 %d
    ",rec[cnt]);rec[cnt--]=0;
            }
            else if(ord==3){
                printf("3 %d
    ",rec[(rand()%cnt)+1]);
            }
            else if(ord==4)
                printf("4 %d
    ",rand()%cnt+1);
            else if(ord==5){
                if(cnt>2000)
                    sort(rec+1,rec+cnt+1,cmp);
                printf("5 %d
    ",rec[(rand()%cnt)+1]+1);
            }
            else if(ord==6){
                //sort(rec+1,rec+cnt+1,cmp);
                printf("6 %d
    ",rec[(rand()%cnt)+1]-1);
            }
        }
        
        return 0;
    }
    View Code

    对拍加油啦...

  • 相关阅读:
    (转)Zipalign——Android apk优化工具
    (转)Android 数字证书详
    (转)ant深入浅出
    (转)Java调用Ant API用法
    (转)Java 代码调用ANT
    (转) Android如果对APK进行加密,提高反编译难度(思路)
    (转)Ant自动打包
    (转)Ant build.xml中的各种变量,使用系统环境变量
    (转)JAVA调用脚本
    (转)Android 编译,打包、签程名详细教
  • 原文地址:https://www.cnblogs.com/Robert-Yuan/p/5061619.html
Copyright © 2020-2023  润新知