题目
给出序列A
求a[1]+min(|a[i]-a[j]|)+…+min(|a[n]-a[j]|){1<=j<=i}
a[i]可能为负数
题解
听所用排序可以水过去
但是为了练习treap,我还是打了treap
就是找出和a[i]最接近的数,转化到treap中即求前驱和后继,然后在两数中选择与a[i]最小的差值计入答案
注意相同的数!!
代码
#include <cstdio>
#include <cstdlib>
#include <algorithm>
#include <cmath>
using namespace std;
struct node{
int l,r;
int size,data,key;
}t[100000];
int n,root,cnt,ans;
const int m=100000000;
void updata(int x){
t[x].size=t[t[x].l].size+t[t[x].r].size+1;
}
void rttn(int &x){
int y=t[x].l;
t[x].l=t[y].r;
t[y].r=x;
updata(x);updata(y);
x=y;
}
void lttn(int &x){
int y=t[x].r;
t[x].r=t[y].l;
t[y].l=x;
updata(x);updata(y);
x=y;
}
void insert(int &x,int k){
if (x==0){
x=++cnt;
t[x].key=rand();
t[x].data=k;
t[x].size=1;
return;
}
if (k<=t[x].data) {
insert(t[x].l,k);
if (t[x].key>t[t[x].l].key) rttn(x);
} else {
insert(t[x].r,k);
if (t[x].key>t[t[x].r].key) lttn(x);
}
updata(x);
}
int pre(int k){
int x=root,ans=-m;
while (x){
if (k==t[x].data) return t[x].data;
if (k>t[x].data) ans=max(ans,t[x].data),x=t[x].r;
else x=t[x].l;
}
return ans;
}
int next(int k){
int x=root,ans=m;
while (x){
if (k==t[x].data) return t[x].data;
if (k<t[x].data) ans=min(t[x].data,ans),x=t[x].l;
else x=t[x].r;
}
return ans;
}
int main(){
scanf("%d",&n);
for (int i=1;i<=n;i++){
int x,pr,ne;
scanf("%d",&x);
pr=pre(x);
ne=next(x);
if (i==1) ans+=abs(x); else ans+=min(x-pr,ne-x);
insert(root,x);
}
printf("%d\n",ans);
}