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

    今天是写平衡树的一天,准备仅使用今天一天的时间了解一下这个模板,不至于比赛的时候出模板题也写不上来

    平衡树是一个很巧妙的数据结构,各种旋转全都是智慧

    Splay与Treap相比各有其巧妙的地方,今天使用题目测试了一下,速度不相上下,相对于我自己而言,更喜欢Treap,小白不求甚解,不知道两者之间有什么精妙的区别

    Splay是通过每次插入之或者修改值的时候对树都进行一次操作,每次都使得树尽可能的均衡,来达到降低时间复杂度的

    每次操作,都将现在查询的节点调到根节点上,就像是搜索引擎一样,对于访问次数多的点就会更快

    左旋右旋依然不改变树的平衡性

    附上自己的模板

    #include<stdio.h>
    #include<iostream>
    #include<algorithm>
    #include<string.h>
    using namespace std;
    const int Maxn = 1000006;
    struct Tree
    {
        int num , key , size , fa ,son[2];
        ///num记录键值等于key的值有多少个 size记录的是子树的节点数目 fa记录的是父亲节点的标号
        /*
        不通过随机值来保持平衡树均衡 而是每次询问都进行双旋
        像搜索引擎一样 询问次数多的就在上面 使得总的复杂度减小
        双旋的过程中使得平衡树均衡 第一次询问的复杂度较高 平均下来就是log级别的
        */
    } T[Maxn];
    int cnt , root;
    int Add[Maxn];
    void init()
    {
        root = 0;
        cnt = 1;
    }
    void PushUp(int x)
    {
        T[x].size = T[T[x].son[0]].size + T[T[x].son[1]].size+T[x].num;
    }
    void PushDown(int x)
    {
        if(Add[x])
        {
            if(T[x].son[0])
            {
                T[T[x].son[0]].key += Add[x];
                Add[T[x].son[0]] += Add[x];
            }
            if(T[x].son[1])
            {
                T[T[x].son[1]].key += Add[x];
                Add[T[x].son[1]] += Add[x];
            }
            Add[x] = 0;
        }
    }
    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)
            {
                Rotate(x , T[T[x].fa].son[0]==x);
            }
            else
            {
                int y = T[x].fa;
                int z = T[y].fa;
                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)
            root = x;
    }
    int Newnode(int key , int fa)  ///新建一个节点
    {
        ++cnt;
        T[cnt].fa = fa;
        T[cnt].key = key;
        T[cnt].num = T[cnt].size = 1;
        T[cnt].son[0] = T[cnt].son[1] = 0;
        return cnt;
    }
    void Insert(int key)   ///插入键值为key的节点
    {
        if( !root )
        {
            root = Newnode(key , 0);
        }
        else
        {
            int now = root , y = 0;
            while( now )
            {
                PushDown(now);
                y = now;
                if(T[now].key == key)
                {
                    T[now].num++;
                    T[now].size++;
                    break;
                }
                T[now].size++;
                now = T[now].son[key>T[now].key];
            }
            if(!now)
            {
                now = T[y].son[key>T[y].key] = Newnode(key,y);
            }
            Splay(now,0); //插入新节点旋转到根节点上来
        }
    }
    int GetPth(int p , int to)    ///找到第p小的节点的标号 若无返回0 并移动到to的子节点上来
    {
        if(root==0 || p>T[root].size)
            return 0;
        int x = root;
        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 , to);
        return x;
    
    }
    int Find(int key)   ///返回键值是key的节点的标号 若无返回0 若有转移到根处
    {
        if(root == 0)
        return 0;
        int x = root;
        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;
    }
    void Del(int key)   ///删除键值是key的节点1个
    {
        int x =Find(key);
        if( !x ) return ;
        if( T[x].num > 1)
        {
            T[x].num--;
            PushUp(x);
            return;
        }
        int y = T[x].son[0];
        while( T[y].son[1] )
            y = T[y].son[1];
        int z = T[x].son[1];
        while( T[z].son[0] )
            z = T[z].son[0];
        if(!y && !z)
        {
            root = 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的节点的个数
    {
        if( !Find(key) )
        {
            Insert(key);
            int tmp = T[T[root].son[0]].size;
            Del(key);
            return tmp;
        }
        else
        {
            return T[T[root].son[0]].size+T[root].num;
        }
    }
    int Prev()  ///返回根节点的前驱(不重要)
    {
        if(!root || !T[root].son[0]) return 0;
        int x = T[root].son[0];
        while( T[x].son[1] )
        {
            PushDown(x);
            x = T[x].son[1];
        }
        Splay(x , 0);
        return x;
    
    }
    int Succ()
    {
        if(!root || !T[root].son[1]) return 0;
        int x = T[x].son[1];
        while( T[x].son[0] )
        {
            PushDown(x);
            x = T[x].son[0];
        }
        Splay(x , 0);
        return x;
    }
    void DelSeq(int l , int r)   ///删除键值在[l,r]中的所有节点 l!=r
    {
        if( !Find(l) )
            Insert(l);
        int p = Prev();
        if( !Find(r) )
            Insert(r);
        int q = Succ();
        if(!p &&!q)
        {
            root = 0;
            return ;
        }
        if( !p )
        {
            T[root].son[0] = 0;
            PushUp(root);
            return ;
        }
        if( !q )
        {
            Splay(p , 0);
            T[root].son[1] = 0;
            PushUp(root);
            return ;
        }
        Splay(p , q);
        T[p].son[1] = 0;
        PushUp(p);
        PushUp(q);
    }
    int GetClose(int key)   ///找到与键值key相差的最小值 返回-1代表树上无值
    {
        if(root == 0)
            return -1;
        int x = root;
        int res = Inf;
        while(x)
        {
            res = min(res , abs(T[x].key-key));
            x = T[x].son[key>T[x].key];
        }
        return res;
    }
    void output(int x)   ///输出所建的平衡树
    {
        printf("%d..%d..%d..%d..%d..%d..
    " ,x , T[x].key , T[x].num , T[x].size , T[x].son[0] , T[x].son[1]);
        if( T[x].son[0] )
            output(T[x].son[0]);
        if(T[x].son[1])
            output(T[x].son[1]);
    }
    int main()
    {
        init();   ///初始化不能忘记
    
        return 0;
    }

    POJ1442

    #include<stdio.h>
    #include<iostream>
    #include<algorithm>
    #include<string.h>
    using namespace std;
    const int Maxn = 1000006;
    struct Tree
    {
        int num , key , size , fa ,son[2];
        ///num记录键值等于key的值有多少个 size记录的是子树的节点数目 fa记录的是父亲节点的标号
        /*
        不通过随机值来保持平衡树均衡 而是每次询问都进行双旋
        像搜索引擎一样 询问次数多的就在上面 使得总的复杂度减小
        双旋的过程中使得平衡树均衡 第一次询问的复杂度较高 平均下来就是log级别的
        */
    } T[Maxn];
    int cnt , root;
    int Add[Maxn];
    void init()
    {
        root = 0;
        cnt = 1;
    }
    void PushUp(int x)
    {
        T[x].size = T[T[x].son[0]].size + T[T[x].son[1]].size+T[x].num;
    }
    void PushDown(int x)
    {
        if(Add[x])
        {
            if(T[x].son[0])
            {
                T[T[x].son[0]].key += Add[x];
                Add[T[x].son[0]] += Add[x];
            }
            if(T[x].son[1])
            {
                T[T[x].son[1]].key += Add[x];
                Add[T[x].son[1]] += Add[x];
            }
            Add[x] = 0;
        }
    }
    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)
            {
                Rotate(x , T[T[x].fa].son[0]==x);
            }
            else
            {
                int y = T[x].fa;
                int z = T[y].fa;
                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)
            root = x;
    }
    int Newnode(int key , int fa)  ///新建一个节点
    {
        ++cnt;
        T[cnt].fa = fa;
        T[cnt].key = key;
        T[cnt].num = T[cnt].size = 1;
        T[cnt].son[0] = T[cnt].son[1] = 0;
        return cnt;
    }
    void Insert(int key)   ///插入键值为key的节点
    {
        if( !root )
        {
            root = Newnode(key , 0);
        }
        else
        {
            int now = root , y = 0;
            while( now )
            {
                PushDown(now);
                y = now;
                if(T[now].key == key)
                {
                    T[now].num++;
                    T[now].size++;
                    break;
                }
                T[now].size++;
                now = T[now].son[key>T[now].key];
            }
            if(!now)
            {
                now = T[y].son[key>T[y].key] = Newnode(key,y);
            }
            Splay(now,0); //插入新节点旋转到根节点上来
        }
    }
    int GetPth(int p , int to)    ///找到第p小的节点的标号 若无返回0 并移动到to的子节点上来
    {
        if(root==0 || p>T[root].size)
            return 0;
        int x = root;
        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 , to);
        return x;
    
    }
    void output(int x)
    {
        printf("%d..%d..%d..%d..%d..%d..
    " ,x , T[x].key , T[x].num , T[x].size , T[x].son[0] , T[x].son[1]);
        if( T[x].son[0] )
            output(T[x].son[0]);
        if(T[x].son[1])
            output(T[x].son[1]);
    }
    int a[Maxn];
    int u[Maxn];
    int main()
    {
        int n , m;
        u[0] = 0;
        while( scanf("%d%d" ,&n ,&m) != EOF )
        {
           for(int i=1; i<=n; i++)
            scanf("%d" , &a[i]);
           for(int i=1; i<=m; i++)
           {
               scanf("%d" , &u[i]);
               for(int j=u[i-1]+1; j<=u[i]; j++)
               {
                Insert(a[j]);
    //               output(root);
    //               printf("
    ");
               }
               printf("%d
    " , T[GetPth(i,0)].key);
           }
        }
    
    
        return 0;
    }
    View Code

    POJ 2352

    #include<stdio.h>
    #include<iostream>
    #include<algorithm>
    #include<string.h>
    using namespace std;
    const int Maxn = 1000006;
    struct Tree
    {
        int num , key , size , fa ,son[2];
        ///num记录键值等于key的值有多少个 size记录的是子树的节点数目 fa记录的是父亲节点的标号
        /*
        不通过随机值来保持平衡树均衡 而是每次询问都进行双旋
        像搜索引擎一样 询问次数多的就在上面 使得总的复杂度减小
        双旋的过程中使得平衡树均衡 第一次询问的复杂度较高 平均下来就是log级别的
        */
    } T[Maxn];
    int cnt , root;
    int Add[Maxn];
    void init()
    {
        root = 0;
        cnt = 1;
    }
    void PushUp(int x)
    {
        T[x].size = T[T[x].son[0]].size + T[T[x].son[1]].size+T[x].num;
    }
    void PushDown(int x)
    {
        if(Add[x])
        {
            if(T[x].son[0])
            {
                T[T[x].son[0]].key += Add[x];
                Add[T[x].son[0]] += Add[x];
            }
            if(T[x].son[1])
            {
                T[T[x].son[1]].key += Add[x];
                Add[T[x].son[1]] += Add[x];
            }
            Add[x] = 0;
        }
    }
    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)
            {
                Rotate(x , T[T[x].fa].son[0]==x);
            }
            else
            {
                int y = T[x].fa;
                int z = T[y].fa;
                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)
            root = x;
    }
    int Newnode(int key , int fa)  ///新建一个节点
    {
        ++cnt;
        T[cnt].fa = fa;
        T[cnt].key = key;
        T[cnt].num = T[cnt].size = 1;
        T[cnt].son[0] = T[cnt].son[1] = 0;
        return cnt;
    }
    void Insert(int key)   ///插入键值为key的节点
    {
        if( !root )
        {
            root = Newnode(key , 0);
        }
        else
        {
            int now = root , y = 0;
            while( now )
            {
                PushDown(now);
                y = now;
                if(T[now].key == key)
                {
                    T[now].num++;
                    T[now].size++;
                    break;
                }
                T[now].size++;
                now = T[now].son[key>T[now].key];
            }
            if(!now)
            {
                now = T[y].son[key>T[y].key] = Newnode(key,y);
            }
            Splay(now,0); //插入新节点旋转到根节点上来
        }
    }
    int Find(int key)   ///返回键值是key的节点的标号 若无返回0 若有转移到根处
    {
        if(root == 0)
        return 0;
        int x = root;
        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;
    }
    void Del(int key)   ///删除键值是key的节点1个
    {
        int x =Find(key);
        if( !x ) return ;
        if( T[x].num > 1)
        {
            T[x].num--;
            PushUp(x);
            return;
        }
        int y = T[x].son[0];
        while( T[y].son[1] )
            y = T[y].son[1];
        int z = T[x].son[1];
        while( T[z].son[0] )
            z = T[z].son[0];
        if(!y && !z)
        {
            root = 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的节点的个数
    {
        if( !Find(key) )
        {
            Insert(key);
            int tmp = T[T[root].son[0]].size;
            Del(key);
            return tmp;
        }
        else
        {
            return T[T[root].son[0]].size+T[root].num;
        }
    }
    int ans[Maxn];
    int main()
    {
        int n , x , y;
        while( scanf("%d" ,&n) != EOF )
        {
            memset(ans , 0 , sizeof(ans));
            for(int i=1; i<=n; i++)
            {
                scanf("%d%d" , &x , &y);
                ans[GetRank(x)]++;
                Insert(x);
            }
            for(int i=0; i<n; i++)
                printf("%d
    " , ans[i]);
        }
    
    
        return 0;
    }
    View Code

    POJ 3481

    #include<stdio.h>
    #include<iostream>
    #include<algorithm>
    #include<string.h>
    
    using namespace std;
    
    const int Maxn = 1000006;
    struct Tree
    {
        int num , key , size , fa ,son[2];
        int id;
        ///num记录键值等于key的值有多少个 size记录的是子树的节点数目 fa记录的是父亲节点的标号
        /*
        不通过随机值来保持平衡树均衡 而是每次询问都进行双旋
        像搜索引擎一样 询问次数多的就在上面 使得总的复杂度减小
        双旋的过程中使得平衡树均衡 第一次询问的复杂度较高 平均下来就是log级别的
        */
    } T[Maxn];
    int cnt , root;
    int Add[Maxn];
    
    void init()
    {
        root = 0;
        cnt = 1;
    }
    void PushUp(int x)
    {
        T[x].size = T[T[x].son[0]].size + T[T[x].son[1]].size+T[x].num;
    }
    void PushDown(int x)
    {
        if(Add[x])
        {
            if(T[x].son[0])
            {
                T[T[x].son[0]].key += Add[x];
                Add[T[x].son[0]] += Add[x];
            }
            if(T[x].son[1])
            {
                T[T[x].son[1]].key += Add[x];
                Add[T[x].son[1]] += Add[x];
            }
            Add[x] = 0;
        }
    }
    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)
            {
                Rotate(x , T[T[x].fa].son[0]==x);
            }
            else
            {
                int y = T[x].fa;
                int z = T[y].fa;
                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)
            root = x;
    }
    int Newnode(int key , int fa , int id)  ///新建一个节点
    {
        ++cnt;
        T[cnt].fa = fa;
        T[cnt].key = key;
        T[cnt].num = T[cnt].size = 1;
        T[cnt].son[0] = T[cnt].son[1] = 0;
        T[cnt].id = id;
        return cnt;
    }
    void Insert(int key , int id)   ///插入键值为key的节点
    {
        if( !root )
        {
            root = Newnode(key , 0 , id);
        }
        else
        {
            int now = root , y = 0;
            while( now )
            {
                PushDown(now);
                y = now;
                if(T[now].key == key)
                {
                    T[now].num++;
                    T[now].size++;
                    break;
                }
                T[now].size++;
                now = T[now].son[key>T[now].key];
            }
            if(!now)
            {
                now = T[y].son[key>T[y].key] = Newnode(key,y,id);
            }
            Splay(now,0); //插入新节点旋转到根节点上来
        }
    }
    int Find(int key)   ///返回键值是key的节点的标号 若无返回0 若有转移到根处
    {
        if(root == 0)
            return 0;
        int x = root;
        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;
    }
    void Del(int key)   ///删除键值是key的节点1个
    {
        int x =Find(key);
        if( !x ) return ;
        if( T[x].num > 1)
        {
            T[x].num--;
            PushUp(x);
            return;
        }
        int y = T[x].son[0];
        while( T[y].son[1] )
            y = T[y].son[1];
        int z = T[x].son[1];
        while( T[z].son[0] )
            z = T[z].son[0];
        if(!y && !z)
        {
            root = 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 Fin(int x , int p)
    {
        if(x == 0)
            return 0;
        while(T[x].son[p])
        {
            x = T[x].son[p];
        }
        return x;
    }
    void output(int x)
    {
        printf("%d..%d..%d..%d..%d..%d.
    " , x , T[x].key , T[x].id , T[x].son[0] , T[x].son[1] , T[x].num);
        if(T[x].son[0])
            output(T[x].son[0]);
        if(T[x].son[1])
            output(T[x].son[1]);
    }
    int main()
    {
        int flag , num , key;
        while( scanf("%d" , &flag) != EOF )
        {
            if(flag == 0)
                break;
            if(flag == 1)
            {
                scanf("%d%d" , &num , &key);
                Insert(key , num);
            }
            else if(flag == 2)
            {
                int tmp = Fin(root , 1);
                if(tmp == 0)
                    printf("0
    ");
                else
                {
                    printf("%d
    " , T[tmp].id);
                    Del(T[tmp].key);
                }
            }
            else if(flag == 3)
            {
                int tmp = Fin(root , 0);
                if(tmp == 0)
                    printf("0
    ");
                else
                {
                    printf("%d
    " , T[tmp].id);
                    Del(T[tmp].key);
                }
            }
        }
    
    
        return 0;
    }
    View Code

    HNOI 2002

    评测地点:http://www.lydsy.com/JudgeOnline/problem.php?id=1588

    题意:给你一个序列,让你找到前面的与他差距最小的数字,将所有位的最小差值求和,就是平衡树上求离他最近的两个点与他的差值求最小值

    这里代码中一个巧妙的地方,从很节点不停的求差值取最小,并且逼近与他相邻的那个值,这样不仅不需要保存最近的两个值,而且一定不会有遗漏

    #include<stdio.h>
    #include<iostream>
    #include<algorithm>
    #include<string.h>
     
    using namespace std;
     
    const int Maxn = 1000006;
    const int Inf = 0x3f3f3f3f;
    struct Tree
    {
        int num , key , size , fa ,son[2];
        ///num记录键值等于key的值有多少个 size记录的是子树的节点数目 fa记录的是父亲节点的标号
        /*
        不通过随机值来保持平衡树均衡 而是每次询问都进行双旋
        像搜索引擎一样 询问次数多的就在上面 使得总的复杂度减小
        双旋的过程中使得平衡树均衡 第一次询问的复杂度较高 平均下来就是log级别的
        */
    } T[Maxn];
    int cnt , root;
    int Add[Maxn];
    void init()
    {
        root = 0;
        cnt = 1;
    }
    void PushUp(int x)
    {
        T[x].size = T[T[x].son[0]].size + T[T[x].son[1]].size+T[x].num;
    }
    void PushDown(int x)
    {
        if(Add[x])
        {
            if(T[x].son[0])
            {
                T[T[x].son[0]].key += Add[x];
                Add[T[x].son[0]] += Add[x];
            }
            if(T[x].son[1])
            {
                T[T[x].son[1]].key += Add[x];
                Add[T[x].son[1]] += Add[x];
            }
            Add[x] = 0;
        }
    }
    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)
            {
                Rotate(x , T[T[x].fa].son[0]==x);
            }
            else
            {
                int y = T[x].fa;
                int z = T[y].fa;
                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)
            root = x;
    }
    int Newnode(int key , int fa)  ///新建一个节点
    {
        ++cnt;
        T[cnt].fa = fa;
        T[cnt].key = key;
        T[cnt].num = T[cnt].size = 1;
        T[cnt].son[0] = T[cnt].son[1] = 0;
        return cnt;
    }
    void Insert(int key)   ///插入键值为key的节点
    {
        if( !root )
        {
            root = Newnode(key , 0);
        }
        else
        {
            int now = root , y = 0;
            while( now )
            {
                PushDown(now);
                y = now;
                if(T[now].key == key)
                {
                    T[now].num++;
                    T[now].size++;
                    break;
                }
                T[now].size++;
                now = T[now].son[key>T[now].key];
            }
            if(!now)
            {
                now = T[y].son[key>T[y].key] = Newnode(key,y);
            }
            Splay(now,0); //插入新节点旋转到根节点上来
        }
    }
    int GetClose(int key)
    {
        if(root == 0)
            return 0;
        int x = root;
        int res = Inf;
        while(x)
        {
            res = min(res , abs(T[x].key-key));
            x = T[x].son[key>T[x].key];
        }
        return res;
    }
    int main()
    {
        int n , num , ans;
        while( scanf("%d" , &n) != EOF )
        {
            scanf("%d" , &num);
            Insert(num);
            ans = num;
            for(int i=2; i<=n; i++)
            {
                scanf("%d" , &num);
                ans += GetClose(num);
                Insert(num);
            }
            printf("%d
    " , ans);
        }
     
        return 0;
    }
    View Code

    推荐  NOI2004  是区间删除的操作  但是没找到地方提交

  • 相关阅读:
    体温填报APP--体温填报
    体温填报APP--主界面设计
    剑指Offer_#60_n个骰子的点数
    剑指Offer_#56-II_ 数组中数字出现的次数II
    剑指Offer_#56-I_数组中数字出现的次数
    剑指Offer_#55
    用Python从头开始构建神经网络
    使用RetinaNet构建的人脸口罩探测器
    如何利用PyTorch中的Moco-V2减少计算约束
    TF2目标检测API
  • 原文地址:https://www.cnblogs.com/Flower-Z/p/9806483.html
Copyright © 2011-2022 走看看