平衡树练手题,我们看它这个数列是动态插入的,所以自然而然就会想到用平衡树来维护。平衡树Splay推荐大家看这篇博客
其实差的最小值只有可能是它与其前驱或后继之差,不然就没有更小的了。因为节点是动态插入的,根据Splay的性质,我们为保证复杂度,就会每次将操作节点旋到根,而他的前驱和后继必然就是之前插入过的数。最后将最小值求和即可。

#include<cstdio>
#include<algorithm>
using namespace std;
const int maxn=1e6+7;
const int INF=0x7fffffff;
int ch[maxn][2];
int n,x;
int rt,sz;
int cnt[maxn],fa[maxn],size[maxn],key[maxn];
int ans;
void pushup(int x){
size[x]=size[ch[x][0]]+size[ch[x][1]]+cnt[x];
}
bool check(int x){
return ch[fa[x]][1]==x;
}
void rotate(int x){
int y=fa[x],z=fa[y],who=check(x);
ch[y][who]=ch[x][who^1];
fa[ch[y][who]]=y;
ch[x][who^1]=y;
fa[y]=x,fa[x]=z;
if(z) ch[z][ch[z][1]==y]=x;
pushup(y),pushup(x);
}
void splay(int x){
for(int f;(f=fa[x]);rotate(x)){
if(fa[f]) rotate((check(f)==check(x))?f:x);
}
rt=x;
}
void insert(int x){
if(!rt){
rt=++sz;
size[sz]=cnt[sz]=1;
key[sz]=x;
return;
}
int now=rt,f=0;
while(1){
if(x==key[now]){
cnt[now]++;
pushup(f);
pushup(now);
splay(now);
return;
}
f=now,now=ch[now][x>key[now]];
if(!now){
sz++;
size[sz]=cnt[sz]=1;
fa[sz]=f;
key[sz]=x;
ch[f][x>key[f]]=sz;
pushup(f);
splay(sz);
return;
}
}
}
int pre(){
int now=ch[rt][0];
if(now==0) return INF;
while(ch[now][1]) now=ch[now][1];
return key[now];
}
int nxt(){
int now=ch[rt][1];
if(now==0) return INF;
while(ch[now][0]) now=ch[now][0];
return key[now];
}
int main(){
scanf("%d",&n);
for(int i=1;i<=n;i++){
scanf("%d",&x);
insert(x);
if(i==1) ans+=x;
else{
if(cnt[rt]>1){
ans+=0;
}
else{
int ans1=abs(x-pre());
int ans2=abs(x-nxt());
ans+=min(ans1,ans2);
}
}
}
printf("%d\n",ans);
return 0;
}
