题目中“最小波动值”的意思是,之前的所有数中与当前数值的差的绝对值最小值是多少。
做法是Splay求前驱和后继:
#include<bits/stdc++.h>
using namespace std;
const int maxn=40005;
struct node{
int fa,ch[2];
int cnt,siz;
int val;
}t[maxn];
int root,cnt,tot;
void rot(int x){
int y=t[x].fa;
int z=t[y].fa;
int k=t[y].ch[1]==x;
t[z].ch[t[z].ch[1]==y]=x;
t[x].fa=z;
t[y].ch[k]=t[x].ch[k^1];
t[t[x].ch[k^1]].fa=y;
t[x].ch[k^1]=y;
t[y].fa=x;
}
void Splay(int x,int goal){
while(t[x].fa!=goal){
int y=t[x].fa,z=t[y].fa;
if(z!=goal)
(t[z].ch[0]==y)^(t[y].ch[0]==x)?rot(x):rot(y);
rot(x);
}
if(goal==0) root=x;
}
inline void ins(int x){
int u=root;
int fa=0;
while(u&&t[u].val!=x){
fa=u;
u=t[u].ch[x>t[u].val];
}
if(u) t[u].cnt++;
else{
u=++tot;
if(fa) t[fa].ch[x>t[fa].val]=u;
t[u].ch[0]=t[u].ch[1]=0;
t[tot].fa=fa;
t[tot].val=x;
t[tot].cnt=1;
t[tot].siz=1;
}
Splay(u,0);
}
inline void Find(int x){
int u=root;
if(!u) return;
while(t[u].ch[x>t[u].val]&&x!=t[u].val) u=t[u].ch[x>t[u].val];
Splay(u,0);
}
int tmp1,tmp2;
void Next(int k,int x){
if(k==0) return;
if(x<=t[k].val){
tmp2=t[k].val;
Next(t[k].ch[0],x);
}else Next(t[k].ch[1],x);
}
void Before(int k,int x){
if(k==0) return;
if(x>=t[k].val){
tmp1=t[k].val;
Before(t[k].ch[1],x);
}else Before(t[k].ch[0],x);
}
int n,a,sum;
int main(){
scanf("%d",&n);
for(int i=1;i<=n;i++){
tmp1=tmp2=0x3f3f3f3f;
tmp1*=-1;
scanf("%d",&a);
Before(root,a);
Next(root,a);
sum+=i==1?a:min(a-tmp1,tmp2-a);
ins(a);
}
printf("%d\n",sum);
return 0;
}