• splay tree旋转操作 hdu 1890


    很神奇的旋转操作。

    目前没看到其他数据结构能实现这个功能。平衡树不好处理区间操作,线段树很难旋转。splay tree搞这个就很简单了。

    下面用的这个模板跑了700ms,好慢,估计是删除操作太费时了,是时候去找找其他更快的模板了。

    #include <stdio.h>
    #include <string.h>
    #include <algorithm>
    #include <iostream>
    using namespace std;
    
    #define MAXN 100100
    
    //好慢啊 优化下
    bool Add[MAXN];//延迟标记
    
    struct Splay_Tree
    {
        int cnt, rt;//cnt为节点数,rt == root
    
        struct Tree{
            int key;//关键字
            int num, size;//num是这个节点有多少重复,size是以这个节点为根的子树大小。
            int fa, son[2];
        }T[MAXN];
    
        inline void init()
        {
            cnt = 0;//初始化超级根节点(标记为0的节点)
            T[0].size = 0;
            rt = 0;
            memset(Add,0,sizeof(Add));//开始初始化0
        }
        inline void PushUp(int x)
        {
            T[x].size=T[T[x].son[0]].size+T[T[x].son[1]].size+T[x].num;
        }
    
        inline void PushDown(int x)
        {
            //翻转操作,这一步最为关键
            if(Add[x])
            {
                if(T[x].son[0])//
                {
                    int son0 = T[x].son[0];
                    //不管那么多,先旋转起来。
                    swap(T[son0].son[0],T[son0].son[1]);
                    Add[son0] ^= 1;
                }
                if(T[x].son[1])
                {
                    int son1 = T[x].son[1];
                    //不管那么多,先旋转起来。
                    swap(T[son1].son[0],T[son1].son[1]);
                    Add[son1] ^= 1;
                }
                Add[x]=0;//不管子节点有没有,这层一定往下推,没有子节点相当于标记无效。
            }
        }
    
        inline int Newnode(int key, int fa) //新建一个节点并返回
        {
            ++cnt;
            T[cnt].key=key;
            T[cnt].num=T[cnt].size=1;
            T[cnt].fa=fa;
            T[cnt].son[0]=T[cnt].son[1]=0;
            return cnt;
        }
    
        inline void Rotate(int x, int p) //0左旋 1右旋
        {
            int y=T[x].fa;
            PushDown(y);//你是说这个有问题。
            PushDown(x);
            T[y].son[!p]=T[x].son[p];
            T[T[x].son[p]].fa=y;
            T[x].fa=T[y].fa;
            if(T[x].fa)
                T[T[x].fa].son[T[T[x].fa].son[1] == y]=x;
            T[x].son[p]=y;
            T[y].fa=x;
            PushUp(y);
            PushUp(x);
        }
    
        void Splay(int x, int To) //将x节点移动到To的子节点中
        {
            while(T[x].fa != To)
            {
                
                if(T[T[x].fa].fa == To)
                {
                    //在这里面得
                    PushDown(T[x].fa);
                    PushDown(x);
                    Rotate(x, T[T[x].fa].son[0] == x);
                }
                else
                {
                    int y=T[x].fa, z=T[y].fa;
                    PushDown(z);
                    PushDown(y);
                    PushDown(x);
                    int p=(T[z].son[0] == y);
                    if(T[y].son[p] == x)
                        Rotate(x, !p), Rotate(x, p); //之字旋
                    else
                        Rotate(y, p), Rotate(x, p); //一字旋
                }
            }
            if(To == 0) rt=x;
        }
    
        int GetPth(int p, int To) //返回第p小的节点 并移动到To的子节点中
        {
            if(!rt || p > T[rt].size) return 0;
            int x=rt;
            while(x)
            {
                PushDown(x);
                if(p >= T[T[x].son[0]].size+1 && p <= T[T[x].son[0]].size+T[x].num)
                    break;
                if(p > T[T[x].son[0]].size+T[x].num)
                {
                    p-=T[T[x].son[0]].size+T[x].num;
                    x=T[x].son[1];
                }
                else
                    x=T[x].son[0];
            }
            Splay(x, 0);
            return x;
        }
    
        int Find(int key) //返回值为key的节点 若无返回0 若有将其转移到根处
        {
            if(!rt) return 0;
            int x=rt;
            while(x)
            {
                PushDown(x);
                if(T[x].key == key) break;
                x=T[x].son[key > T[x].key];
            }
            if(x) Splay(x, 0);
            return x;
        }
    
        int Prev() //返回根节点的前驱 非重点
        {
            if(!rt || !T[rt].son[0]) return 0;
            int x=T[rt].son[0];
            while(T[x].son[1])
            {
                PushDown(x);
                x=T[x].son[1];
            }
            Splay(x, 0);
            return x;
        }
    
        int next() //返回根结点的后继 非重点
        {
            if(!rt || !T[rt].son[1]) return 0;
            int x=T[rt].son[1];
            while(T[x].son[0])
            {
                PushDown(x);
                x=T[x].son[0];
            }
            Splay(x, 0);
            return x;
        }
    
        void Insert(int key) //插入key值
        {
            if(!rt)
                rt=Newnode(key, 0);
            else
            {
                int x=rt, y=0;
                while(x)
                {
                    PushDown(x);
                    y=x;
                    if(T[x].key == key)
                    {
                        T[x].num++;
                        T[x].size++;
                        break;
                    }
                    T[x].size++;//既然一定调整
                    x=T[x].son[key > T[x].key];
                }
                if(!x)
                    x = T[y].son[key > T[y].key] = Newnode(key, y);
                Splay(x, 0);
            }
        }
    
        void Delete(int key)
        {
            //我知道什么错误了,删除一个节点前,需要先将这个点splay 到根
            int x = key;
            if(!x) return;
            Splay(x, 0);
            if(T[x].num>1)
            {
                T[x].num--;
                PushUp(x);
                return;
            }
            int y=T[x].son[0];
            PushDown(y);
            //终于找到了,只要往下找就得pushdown
            while(T[y].son[1])
            {
                y=T[y].son[1];
                PushDown(y);
            }
            int z=T[x].son[1];
            PushDown(z);
            while(T[z].son[0])
            {
                z=T[z].son[0];
                PushDown(z);
            }
            if(!y && !z)
            {
                rt=0;
                return;
            }
            if(!y)
            {
                Splay(z, 0);
                T[z].son[0]=0;
                PushUp(z);
                return;
            }
            if(!z)
            {
                Splay(y, 0);
                T[y].son[1]=0;
                PushUp(y);
                return;
            }
            Splay(y, 0);
            Splay(z, y);//前驱和后继相同是什么鬼
            T[z].son[0]=0;
            PushUp(z);
            PushUp(y);
        }
    
    //    int GetRank(int key) //获得值<=key的节点个数 并将其转移到根处 若<key只需将<=换为<
    //    {
    //        //我没有写PUSH_UP 和 PUSH_DOWN
    //        if(!rt) return 0;
    //        int x=rt, ret=0, y=0;
    //        while(x)
    //        {
    //            y=x;
    //            if(T[x].key <= key)
    //            {
    //                ret += T[T[x].son[0]].size + T[x].num;
    //                x=T[x].son[1];
    //            }
    //            else
    //                x=T[x].son[0];
    //        }
    //        Splay(y, 0);
    //        return ret;
    //    }
    
    //    这个删除太丑了
    //    void Delete(int l, int r) //删除值在[l, r]中的所有节点 l!=r
    //    {
    //        if(!Find(l)) Insert(l);// 你这样写真的好吗? 泥煤
    //        int p=Prev();
    //        if(!Find(r)) Insert(r);
    //        int q=next();
    //        if(!p && !q)
    //        {
    //            rt=0;
    //            return;
    //        }
    //        if(!p)
    //        {
    //            T[rt].son[0]=0;
    //            PushUp(rt);
    //            return;
    //        }
    //        if(!q)
    //        {
    //            Splay(p, 0);
    //            T[rt].son[1]=0;
    //            PushUp(rt);
    //            return;
    //        }
    //        Splay(p, q);
    //        T[p].son[1]=0;
    //        PushUp(p);
    //        PushUp(q);
    //    }
        
        void display(int x)
        {
            if(x==0) return ;
            PushDown(x);
            display(T[x].son[0]);
            //printf("%d ",T[x].key);
            display(T[x].son[1]);
        }
        
    }spt;
    
    struct node
    {
        int key;
        int id;
    }g[MAXN];
    
    int cmp(node t1,node t2)
    {
        if(t1.key == t2.key) return t1.id<t2.id;
        return t1.key<t2.key;
    }
    
    int main() {
        //SPT 独特的旋转操作!
        int n;
        //printf("nishi sb?");
        while(scanf("%d",&n) && n)
        {
            spt.init();
            for(int i=1;i<=n;i++)
            {
                int tmp;
                scanf("%d",&tmp);
                g[i].key = tmp;
                g[i].id = i;
                spt.Insert(i);
                //只是默认了,每个数字的id 就是它在splay 中对应的下标
            }
            //死循环什么鬼。
            //printf("nishi sb ma?");
            sort(g+1,g+1+n,cmp);
            for(int i=1;i<=n;i++)//开始旋转
            {
                //step one 将当前最小的点,移动到树根处
                spt.Splay(g[i].id, 0);
                //spt.display(spt.rt);
                //printf("
    ");
                //step two 将整个左子树旋转
                int sonid = spt.T[g[i].id].son[0];
                printf("%d",spt.T[sonid].size+i);
                if(i!=n) printf(" ");
                if(sonid != 0)
                {
                    swap(spt.T[sonid].son[0],spt.T[sonid].son[1]);
                    
                    Add[sonid] ^= 1;
                }
                //这里那里GG了,果真还是这里有问题。
                //第一次就删除了两个,不能看
                //spt.display(spt.rt);
                //printf("
    ");
                spt.Delete(g[i].id);
                //每次操作之后,都把结果打印一遍
                //spt.display(spt.rt);
                //printf("
    ");
            }
            printf("
    ");
        }
        return 0;
    }
  • 相关阅读:
    不可重叠最长重复子串
    离散化
    hash是一门优雅的暴力
    Detect the Virus (字符串转化+AC自动机)
    病毒侵袭(AC自动机变形)
    hdu2069(Coin Change)
    Hie with the Pie(poj3311)
    poj3254(状压dp入门第一道题,很详细)
    map系统学习
    ACM-ICPC 2018 南京赛区网络预赛 B. The writing on the wall
  • 原文地址:https://www.cnblogs.com/chenhuan001/p/5343242.html
Copyright © 2020-2023  润新知