zoukankan      html  css  js  c++  java
  • 平衡树Splay

    维护区间添加,删除,前驱,后继,排名,逆排名 普通平衡树

    #include <cstdio>
    #define ls t[now].ch[0]
    #define rs t[now].ch[1]
    int min(int x,int y){return x<y?x:y;}
    int max(int x,int y){return x>y?x:y;}
    const int inf=0x3f3f3f3f;
    const int N=100010;
    struct Splay
    {
        int par,ch[2],dat,siz,cnt;
    }t[N];
    int tot=0,root,t_size=0;
    int identity(int x)//是父亲的左0/右1孩子
    {
        return t[t[x].par].ch[0]==x?0:1;
    }
    void connect(int fa,int s,int typ)//建立父子关系
    {
        t[fa].ch[typ]=s;
        t[s].par=fa;
    }
    void updata(int now)
    {
        t[now].siz=t[ls].siz+t[rs].siz+t[now].cnt;
    }
    void rotate(int p,int typ)//0左上旋,1右上旋
    {
        int q=t[p].ch[typ];//要转的儿子
        connect(p,t[q].ch[typ^1],typ);//顺序不能换,得注意一下
        connect(t[p].par,q,identity(p));
        connect(q,p,typ^1);
        updata(p),updata(q);//顺序不能换
    }
    void splay(int v,int u)//把v位置调整至u
    {
        u=t[u].par;
        while(t[v].par!=u)
        {
            int f=t[v].par,g=t[f].par;
            if(g==u||identity(v)!=identity(f))
                rotate(f,identity(v));
            else
            {
                rotate(g,identity(f));
                rotate(f,identity(v));
            }
        }
    }
    int New(int dat,int fa)
    {
        t[++tot].par=fa,t[tot].dat=dat,t[tot].cnt=1,t[tot].siz=1,t_size++;
        return tot;
    }
    void free(int x)
    {
        t[x].siz=0,t[x].dat=0,t[x].cnt=0,t[x].par=0,t[x].ch[0]=0,t[x].ch[1]=0;
        if(x==tot) tot--;
    }
    void insert(int dat)
    {
        if(!t_size) {root=New(dat,0);connect(0,tot,1);return;}//特判建虚根
        int now=root,las;
        while(1)
        {
            int tpy=t[now].dat>dat?0:1;
            t[now].siz++;
            las=now;
            now=t[now].ch[tpy];
            if(!now)
            {
                now=New(dat,las);
                t[las].ch[tpy]=now;
                break;
            }
            if(t[now].dat==dat)
            {
                t[now].cnt++;
                break;
            }
        }
        splay(now,root);
        root=now;
    }
    int find(int dat)//查找并调整
    {
        int now=root;
        while(1)
        {
            if(t[now].dat==dat)
            {
                splay(now,root);//调整位置至根
                root=now;
                return now;
            }
            int typ=t[now].dat>dat?0:1;
            now=t[now].ch[typ];
        }
    }
    int g_max(int now)
    {
        return t[now].ch[1]?g_max(t[now].ch[1]):now;
    }
    void extrack(int dat)
    {
        int loc=find(dat);//找到删除节点位置并伸展
        if(t[loc].cnt>1) {t[loc].cnt--;t[loc].siz--;return;}//删除一个值并更新
        t_size--;//整棵树的大小--
        if(!t[root].ch[0]) {root=t[root].ch[1];return;}//左子树空拿右子树顶
        loc=g_max(t[root].ch[0]);//找到左子树最大值的位置
        splay(loc,t[root].ch[0]);//把左子树最大值伸展至根节点
        connect(t[root].ch[0],t[root].ch[1],1);//建立联系
        loc=root;//记录一下原根以便free
        root=t[root].ch[0];//更新根节点
        connect(0,root,1);//与虚根建立关系
        updata(root);//更新大小
        free(loc);//释放原根
    }
    void get_rank(int x)//查询x的排名
    {
        root=find(x);
        printf("%d
    ",t[t[root].ch[0]].siz+1);
    }
    void fget_rank(int x)//排名为x的数
    {
        int now=root;
        while(1)
        {
            if(t[ls].siz<x&&x<=t[ls].siz+t[now].cnt) {printf("%d
    ",t[now].dat);return;}
            else if(x>t[ls].siz+t[now].cnt) {x-=t[ls].siz+t[now].cnt;now=rs;}
            else now=ls;
        }
    }
    void get_pre(int x)
    {
        int m_max=-inf,now=root;
        while(now)
        {
            if(t[now].dat<x) {m_max=max(m_max,t[now].dat);now=rs;}
            else now=ls;
        }
        printf("%d
    ",m_max);
    }
    void get_suc(int x)
    {
        int m_min=inf,now=root;
        while(now)
        {
            if(t[now].dat>x) {m_min=min(m_min,t[now].dat);now=ls;}
            else now=rs;
        }
        printf("%d
    ",m_min);
    }
    int main()
    {
        int opt,x,n;
        scanf("%d",&n);
        for(int i=1;i<=n;i++)
        {
            scanf("%d%d",&opt,&x);
            if(opt==1)
                insert(x);
            else if(opt==2)
                extrack(x);
            else if(opt==3)
                get_rank(x);//查询x的排名
            else if(opt==4)
                fget_rank(x);//查询排名为x的数
            else if(opt==5)
                get_pre(x);
            else
                get_suc(x);
        }
        return 0;
    }
    
    

    以上为2018.6.12版本


    #include <cstdio>
    #define ls t[now].ch[0]
    #define rs t[now].ch[1]
    #define f t[now].par
    const int N=100010;
    const int inf=0x3f3f3f3f;
    int min(int x,int y){return x<y?x:y;}
    int max(int x,int y){return x>y?x:y;}
    struct Splay
    {
        int ch[2],par,siz,cnt,dat;
    }t[N];
    int root,wh_siz=0,tot=0;
    int identity(int now)
    {
        return t[f].ch[1]==now;
    }
    void connect(int fa,int now,int typ)
    {
        t[now].par=fa;
        t[fa].ch[typ]=now;
    }
    void updata(int now)
    {
        t[now].siz=t[ls].siz+t[rs].siz+t[now].cnt;
    }
    void rotate(int now)//把now旋转给它父亲
    {
        int typ=identity(now),p=f;
        connect(p,t[now].ch[typ^1],typ);
        connect(t[p].par,now,identity(p));
        connect(now,p,typ^1);
        updata(p),updata(now);
    }
    void splay(int now,int to)
    {
        to=t[to].par;
        for(;f!=to;rotate(now))
            if(t[f].par!=to)
                rotate(identity(now)==identity(f)?f:now);
        if(!to) root=now;
    }
    int New(int dat)
    {
        t[++tot].dat=dat;t[tot].cnt=1;t[tot].siz=1,wh_siz++;
        return tot;
    }
    void free(int now)
    {
        t[now].dat=0,t[now].siz=0,t[now].par=0,t[now].cnt=0,ls=0,rs=0,wh_siz--;
        if(tot==now) tot--;
    }
    void insert(int dat)
    {
        if(!wh_siz) {connect(0,root=New(dat),1);return;}
        int now=root,las;
        while(2333)
        {
            if(t[now].dat==dat) {t[now].siz++;t[now].cnt++;break;}
            int tpy=t[now].dat<dat;
            t[now].siz++;
            las=now;now=t[now].ch[tpy];
            if(!now) {connect(las,now=New(dat),tpy);break;}
        }
        splay(now,root);
    }
    int find(int dat)
    {
        int now=root;
        for(int tpy;t[now].dat!=dat;now=t[now].ch[tpy])
            tpy=t[now].dat<dat;
        splay(now,root);
        return now;
    }
    int g_max(int now)
    {
        return rs?g_max(rs):now;
    }
    void extrack(int dat)
    {
        int now=find(dat);
        if(t[now].cnt>1) {t[now].cnt--;return;}
        if(!ls) {root=rs;connect(0,root,1);free(now);return;}
        int rt=g_max(ls);//新根
        splay(rt,ls);
        root=rt;
        connect(rt,rs,1);
        connect(0,rt,1);
        free(now);
    }
    void pre(int dat)
    {
       int now=root,m_max=-inf;
       for(int typ;now;now=t[now].ch[typ])
            typ=t[now].dat<dat?m_max=max(m_max,t[now].dat),1:0;
       printf("%d
    ",m_max);
    }
    void suc(int dat)
    {
       int now=root,m_min=inf;
       for(int typ;now;now=t[now].ch[typ])
            typ=t[now].dat>dat?m_min=min(m_min,t[now].dat),0:1;
       printf("%d
    ",m_min);
    }
    void rank(int x)//查询排名为x的数
    {
        int now=root;
        while(2333)
        {
            if(x<=t[ls].siz) now=ls;
            else if(x>t[ls].siz+t[now].cnt) x-=t[ls].siz+t[now].cnt,now=rs;
            else {printf("%d
    ",t[now].dat);return;}
        }
    }
    void frank(int dat)//查询dat的排名
    {
        int now=find(dat);
        printf("%d
    ",t[ls].siz+1);
    }
    int main()
    {
        int n,x,opt;
        scanf("%d",&n);
        for(int i=1;i<=n;i++)
        {
            scanf("%d%d",&opt,&x);
            if(opt==1) insert(x);
            else if(opt==2) extrack(x);
            else if(opt==3) frank(x);
            else if(opt==4) rank(x);
            else if(opt==5) pre(x);
            else suc(x);
        }
        return 0;
    }
    

    以上为2018.6.13版本


    维护区间翻转:文艺平衡树

    #include <cstdio>
    #include <iostream>
    #define ls t[now].ch[0]
    #define rs t[now].ch[1]
    #define f t[now].par
    #define s t[now].ch[typ]
    const int N=100010;
    int root,n,m;
    struct Splay
    {
        int c,ch[2],par,siz,tag;
    }t[N];
    int identity(int now)
    {
        return t[f].ch[1]==now;
    }
    void connect(int fa,int now,int typ)
    {
        f=fa;
        t[f].ch[typ]=now;
    }
    void updata(int now)
    {
        t[now].siz=t[ls].siz+t[rs].siz+1;
    }
    void push_down(int now)
    {
        if(now&&t[now].tag)
        {
            t[ls].tag^=1;
            t[rs].tag^=1;
            t[now].tag=0;
            std::swap(ls,rs);
        }
    }
    void rotate(int now)
    {
        push_down(f),push_down(now);
        int p=f,typ=identity(now);
        connect(p,t[now].ch[typ^1],typ);
        connect(t[p].par,now,identity(p));
        connect(now,p,typ^1);
        updata(p),updata(now);
    }
    void splay(int now,int to)
    {
        to=t[to].par;
        for(int typ;f!=to;rotate(now))
            if(t[f].par!=to)
                rotate(identity(now)==identity(f)?f:now);
        if(!to) root=now;
    }
    int build(int l,int r,int fa)
    {
        if(l>r) return 0;
        int now=l+r>>1;
        t[now].c=now-1;
        t[now].par=fa;
        updata(now);
        if(l==r) return now;
        ls=build(l,now-1,now);
        rs=build(now+1,r,now);
        updata(now);
        return now;
    }
    int find(int siz)
    {
         int now=root;
         for(int typ;;now=s)
         {
             push_down(now);
             if(t[ls].siz>=siz) typ=0;
             else if(t[ls].siz+1<siz) siz-=t[ls].siz+1,typ=1;
             else return now;
         }
    }
    void turn(int l,int r)
    {
        int L=find(l-1),R=find(r+1);
        splay(R,root);
        splay(L,t[root].ch[0]);
        t[t[L].ch[1]].tag^=1;
    }
    void write(int now)
    {
        if(!now) return;
        push_down(now);
        write(ls);
        if(t[now].c!=0&&t[now].c!=n+1)
            printf("%d ",t[now].c);
        write(rs);
    }
    int main()
    {
        int l,r;
        scanf("%d%d",&n,&m);
        connect(0,root=build(1,n+2,0),1);
        for(int i=1;i<=m;i++)
        {
            scanf("%d%d",&l,&r);
            turn(l+1,r+1);
            //write(root);
        }
        write(root);
        return 0;
    }
    
    

    2018.6.14

  • 相关阅读:
    超经典~超全的jQuery插件大全
    如何用PHP做到页面注册审核
    php实现签到功能
    php中的实用分页类
    微信小程序,超能装的实例教程
    php之 常用的 流程管理
    php之 人员的权限管理(RBAC)
    php之简单的文件管理(基本功能)
    php最新学习-----文件的操作
    关于LAMP的配置之(虚拟机的安装、创建、配置)
  • 原文地址:https://www.cnblogs.com/butterflydew/p/9175582.html
Copyright © 2011-2022 走看看