读一个数,求出前面的所有数与这个数的相差最小是多少。
N≤105
线段树可以做,然而我用来splay练手
原本我不会模板,自己乱打,不成体统,这是下面是alan教我的方法
读入就insert,求出前驱后继,分别比较去较小,累计到答案。
insert是递归版的,大概就是在splay上面二分。
求pre和suf就把x旋到根,从根往下走即可。
#include
#include
#define fo(i,a,b) for(int i=a;i<=b;i++)
using namespace std;
const int N=100010,INF=2147483647;
int n,p,q,root,tot,f[N],t[N][2],key[N];
bool pd(int x)
{
return x==t[f[x]][1];
}
void insert(int &x,int y,int fa)
{
if(!x)
{
x=++tot,key[x]=y,f[x]=fa;
return;
}
if(y0],y,x);
else insert(t[x][1],y,x);
}
void rotate(int x)
{
int y=f[x],z=pd(x);
t[y][z]=t[x][1-z];
if(t[x][1-z]) f[t[x][1-z]]=y;
f[x]=f[y];
if(f[y]) t[f[y]][pd(y)]=x;
f[y]=x,t[x][1-z]=y;
}
void splay(int x,int y)
{
while(f[x]!=y)
{
if(f[f[x]]!=y)
if(pd(x)==pd(f[x])) rotate(f[x]);
else rotate(x);
rotate(x);
}
if(!y) root=x;
}
int pre(int x)
{
for(x=t[x][0];t[x][1];x=t[x][1]);
return x;
}
int suf(int x)
{
for(x=t[x][1];t[x][0];x=t[x][0]);
return x;
}
int main()
{
int x,ans;
scanf("%d",&n);
scanf("%d",&x);
ans=x;
insert(root,x,0);
fo(i,2,n)
{
scanf("%d",&x);
insert(root,x,0);
splay(tot,0);
int l=pre(root);
if(!l) p=INF;else p=x-key[l];
int r=suf(root);
if(!r) q=INF;else q=key[r]-x;
ans+=min(p,q);
}
printf("%d",ans);
return 0;
}