[HNOI2002] 营业额统计 题解

题解:

题目意思就是让我们在已有的序列里找大于现在要插入的数的最小值,和小于现在要插入的数的最大值,取其差值相减较小者加入答案中。我们可以用BST(二叉查找树)来维护这个序列。这里用Slpay。

附上代码:

#include<bits/stdc++.h>
using namespace std;
const int N=1<<16;

int ch[N][2],f[N],key[N];
int rt,sz,ans;

int get(int x){return ch[f[x]][1]==x;}
    
void rotate(int x){
    int fa=f[x],gfa=f[fa],now=get(x);
    ch[fa][now]=ch[x][now^1],f[ch[fa][now]]=fa;
    ch[x][now^1]=fa,f[fa]=x;
    f[x]=gfa;
    if(gfa) ch[gfa][ch[gfa][1]==fa]=x;
    return;
}

void splay(int x){
    for(int fa;fa=f[x];rotate(x)){
        if(f[fa])
            rotate(get(x)==get(fa) ? fa:x);
    }
    rt=x;
}

int pre(){
    int now=ch[rt][0];
    while(ch[now][1]) now=ch[now][1];
    return now;
}

int next(){
    int now=ch[rt][1];
    while (ch[now][0]) now=ch[now][0];
    return now;
}

int insert(int x){
    if(!rt){
        rt=++sz;
        key[sz]=x;
        return x;
    }
    int now=rt,fa=0;
    while(1){
        if(key[now]==x){
            splay(now);
            return 0;
        }
        fa=now;now=ch[now][x>key[now]];
        if(!now){
            ch[fa][x>key[fa]]=++sz;
            ch[sz][0]=ch[sz][1]=0;
            f[sz]=fa,key[sz]=x;
            splay(sz);
            int k1=pre(),k2=next();
            if(k1 && k2) return min(x-key[k1],key[k2]-x);
            if(k1) return x-key[k1];
            if(k2) return key[k2]-x;
        }
    }
}

int n;
int main(){
    scanf("%d",&n);
    for(int i=1,ai;i<=n;++i){
        scanf("%d",&ai);
        ans+=insert(ai);
    }
    printf("%d",ans);
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/Asika3912333/p/11760869.html