平衡树-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  是区间删除的操作  但是没找到地方提交

原文地址:https://www.cnblogs.com/Flower-Z/p/9806483.html