/*
bzoj1588 splay
Author:lcy
Time:2017-10-11
264ms...好慢
splay裸题,每次把新值加入树中时,获取他的排名,然后
找到排前一位和后一位的值分别和他做差,取最小值后加到答案上
每个节点用一个cnt记录相同元素的个数。
*/
#include <bits/stdc++.h>
using namespace std;
#define ll long long
#define fr(i,a,b) for(int i=a;i<=b;i++)
#define frr(i,a,b) for(int i=a;i>=b;i--)
#define ms(a,b) memset(a,b,sizeof(a))
#define scfd(a) scanf("%d",a)
#define scflf(a) scanf("%lf",a)
#define scfs(a) scanf("%s",a)
#define ptfd(a) printf("%d\n",a)
#define ptfs(a) printf("%s\n",a)
#define showd(a,b) printf(a"=%d\n",b)
#define showlf(a,b) printf(a"=%lf\n",b)
#define shows(a,b) printf(a"=%s\n",b)
#define mmcp(a,b) memcpy(a,b,sizeof(b))
#define pb(a) push_back(a)
struct node{
    node *ch[2];//child
    int v;//value
    int s;//size
    int cnt;
    int cmp(int x){//该点与s比较,如果小于s返回0,即转向左子树
        if(ch[0]&&x<=ch[0]->s)
            return 0;
        if(ch[0]&&x<=ch[0]->s+cnt)
            return -1;
        if(!ch[0]&&x<=cnt)//没有左子树
            return -1;
        return 1;
    }
    void maintain(){
        s=cnt;
        if(ch[0]!=NULL)
            s+=ch[0]->s;
        if(ch[1]!=NULL)
            s+=ch[1]->s;
    }
    node(int x){
        ch[0]=ch[1]=NULL;
        cnt=s=1;
        v=x;
    }
};
int n,rank,ans;
struct splaytree{
    node *root;
    void rotate(node* &o,int d){//把根节点o的d儿子旋转上来
        if(o->ch[d]==NULL)return;
        node *s=o->ch[d];
        o->ch[d]=s->ch[d^1];s->ch[d^1]=NULL;
        s->ch[d^1]=o;
        o=s;
        o->ch[d^1]->maintain();
        o->maintain();
    }
    void splay(node* &o,int k){
        //printf("now=%d,rk=%d\n",o->v,k);
        int d=o->cmp(k);
        if(d==1){k-=o->cnt;if(o->ch[0])k-=o->ch[0]->s;}
        if(~d){
            int dd=o->ch[d]->cmp(k);
            if(~dd){
                int kk=k;
                if(dd==1){kk-=o->ch[d]->cnt;if(o->ch[d]->ch[0])kk-=o->ch[d]->ch[0]->s;}
                splay(o->ch[d]->ch[dd],kk);
                if(d==dd)//共线时先转上面的
                    rotate(o,d);
                else //折线时先转下面的
                    rotate(o->ch[d],dd);
            }
            rotate(o,d);//两种方法最后都要转上面的
        }
    }
    int _push(node* &o,int x,int rk){
        if(o==NULL){root=new node(x);return 1;}//树为空
        int d;
        if(x>o->v){d=1;rk+=o->cnt;if(o->ch[0])rk+=o->ch[0]->s;}
        else if(x==o->v){rk+=o->cnt;o->cnt++;if(o->ch[0])rk+=o->ch[0]->s;o->maintain();return rk;}//相同元素不处理
        else d=0;
        if(o->ch[d]){
             int ans=_push(o->ch[d],x,rk);
             o->maintain();
             return ans;
        }
        else{
            o->ch[d]=new node(x);
            o->maintain();
            return rk;
        }
    }
    inline void push(int x){
        splay(root,(rank=_push(root,x,1)));
    }
    int kth(node* &o,int k){
        int d=o->cmp(k);
        //printf("now=%d,k=%d\n",o->v,k);
        switch(d){
            case -1:
                return o->v;
            case 0:
                return kth(o->ch[0],k);
            case 1:
                int kk=k-o->cnt;
                if(o->ch[0])kk-=o->ch[0]->s;
                return kth(o->ch[1],kk);
        }
    }
    void show(){
        printf("DFS---------------\n");
        dfs(root);
        printf("END---------------\n");
    }
    void dfs(node *o){
        printf("now=%d,size=%d\n",o->v,o->s);
        if(o->ch[0])
            printf("left son %d\n",o->ch[0]->v);
        if(o->ch[1])
            printf("right son %d\n",o->ch[1]->v);
        if(o->ch[0])dfs(o->ch[0]);
        if(o->ch[1])dfs(o->ch[1]);
    }
}spt;
int main(){
    scfd(&n);
    fr(i,1,n){
        int a;
        scfd(&a);
        spt.push(a);
        //spt.show();
        if(i==1)ans+=a;
        else{
            int t=2147483640;
            if(rank>1)
                t=min(abs(a-spt.kth(spt.root,rank-1)),t);
            if(rank<i)
                t=min(abs(a-spt.kth(spt.root,rank+1)),t);
            ans+=t
        }
    }
    ptfd(ans);
    return 0;
}
 posted on 2017-10-11 19:22  cylcy  阅读(189)  评论(0编辑  收藏  举报