zoukankan      html  css  js  c++  java
  • bzoj3224 splay板子

    开始学习新知识:splay——tree

    是个板子题,学习splay可以看博客

    https://blog.csdn.net/Clove_unique/article/details/50630280

    #include<iostream>
    #include<cstring>
    #include<cstdio>
    using namespace std;
    #define MAXN 1000000
    int ch[MAXN][2],f[MAXN],size[MAXN],cnt[MAXN],key[MAXN];
    int sz,root;
    inline void clear(int x){
        ch[x][0]=ch[x][1]=f[x]=size[x]=cnt[x]=key[x]=0;
    }
    inline bool get(int x){
        return ch[f[x]][1]==x;
    }
    inline void update(int x){//更新结点x的size
        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]];
        }
    }
    inline void rotate(int x){//一次旋转
        //得到x的父亲,爷爷,是不是左子树
        int old=f[x],oldf=f[old],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);//不要忘记更新size
    }
    inline void splay(int x){
        for(int fa;fa=f[x];rotate(x))//再把x翻上来
            if(f[fa])//如果fa非根,且x和fa是同一侧,那么先翻转fa,否则先翻转x 
                rotate((get(x)==get(fa))?fa:x);
    
        root=x;//最后把x设为root    
    }
    inline 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;//把now置顶
            }
            fa=now;
            now=ch[now][key[now]<x];//往下搜索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);//把sz置顶
                break;
            }
        }
    }
    inline 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);
                //找到对应的键值,置顶now,返回
                if(x==key[now]){splay(now);return ans+1;} 
                ans+=cnt[now];
                now=ch[now][1];//往右子树
            }    
        }
    }
    inline 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 temp=(ch[now][0]?size[ch[now][0]]:0)+cnt[now];//
                if(x<=temp) 
                    return key[now];
                x-=temp;now=ch[now][1];//往右子树搜索
            }    
        }        
    }        
    inline int pre(){//前驱即左子树里的最大值
        int now=ch[root][0];
        while(ch[now][1]) now=ch[now][1];
        return now;
    }
    inline int next(){//后继是右子树里的最小值
        int now=ch[root][1];
        while(ch[now][0]) now=ch[now][0];
        return now;
    }
    inline void del(int x){
        int whatever=find(x);//只是把x置顶
        //x的个数>1
        if(cnt[root]>1){cnt[root]--;update(root);return;}
        //单个x
        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;
        }
        if(!ch[root][1]){
            int oldroot=root;root=ch[root][0];f[root]=0;clear(oldroot);return;
        }
        //前驱作为根(前驱是没有右儿子的),右子树挂到前驱的右子树,删掉根
        else {
            int pree=pre(),oldroot=root;
            splay(pree);
            ch[root][1]=ch[oldroot][1];
            f[ch[oldroot][1]]=pree;
            clear(oldroot);
            update(pree);
        }
    }
    int main(){
        int n,op,x;
        scanf("%d",&n);
        for(int i=1;i<=n;i++){
            scanf("%d%d",&op,&x);
            switch(op){
                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[next()]);del(x);break;
            }
        }
    }
  • 相关阅读:
    Java关键字transient和volatile小结(转)
    1、环境
    SSH框架搭建
    2.4 easyui
    PHP操作大文件
    PHP小工具
    PHP正则替换函数收集
    PHP小知识收集
    Yii ACF(accessController)简单控权
    linux 文件存放目录
  • 原文地址:https://www.cnblogs.com/zsben991126/p/9982517.html
Copyright © 2011-2022 走看看