Description
给出n个数,求每个数和它前面每个数的差值绝对值的最小值之和。
n<=32767
Solution
很显然求前驱后驱。
可以离散化后用权值线段树二分找。
也可以直接用splay找。
或者还可以离线排完序用双向链表找。
你喜欢就好喽。。。
Orz bzoj上rank1 0ms踩所有人
Code
#include<cstdio>
#include<cstring>
#include<algorithm>
#define fo(i,a,b) for(int i=a;i<=b;i++)
#define N 50005
using namespace std;
const int inf=0x7fffffff;
int n,x,a,b,ans,tot,root,t[N][2],f[N],key[N];
void insert(int &v,int y,int fa) {
if (!v) {v=++tot;key[v]=y;f[v]=fa;return;}
if (key[v]>y) insert(t[v][0],y,v);
else insert(t[v][1],y,v);
}
int son(int x) {return t[f[x]][1]==x;}
void rotate(int x) {
int y=f[x],z=son(x);f[x]=f[y];
if (f[x]) t[f[x]][son(y)]=x;
if (t[x][1-z]) f[t[x][1-z]]=y;
f[y]=x;t[y][z]=t[x][1-z];t[x][1-z]=y;
}
void splay(int x,int y) {
while (f[x]!=y) {
if (f[f[x]]!=y)
if (son(x)==son(f[x])) rotate(f[x]);
else rotate(x);
rotate(x);
}
if (!y) root=x;
}
int pre(int x) {
x=t[x][0];
while (x) {
if (t[x][1]) x=t[x][1];
else break;
}
return x;
}
int suf(int x) {
x=t[x][1];
while (x) {
if (t[x][0]) x=t[x][0];
else break;
}
return x;
}
int main() {
scanf("%d",&n);
scanf("%d",&x);
insert(root,x,0);ans=x;
fo(i,2,n) {
scanf("%d",&x);
insert(root,x,0);splay(tot,0);
int l=pre(root);if (l) a=x-key[l];else a=inf;
int r=suf(root);if (r) b=key[r]-x;else b=inf;
ans+=min(a,b);
}
printf("%d",ans);
}