题意:给出序列a,a[i]的贡献为:min(abs(a[i]-a[j])) (j=1..i-1)
n<=3e4,a[i]<=1e6,求出总贡献?
当计算a[i]贡献时 找前面第一个比它大的,最后一个比它小的? 用set维护.
n<=3e4,a[i]<=1e6,求出总贡献?
当计算a[i]贡献时 找前面第一个比它大的,最后一个比它小的? 用set维护.
或者建立splay,中序遍历是递增的,把x旋转到根,从根开始找x左子树最右边的,x右子树最左边的即可.
#include <bits/stdc++.h>
using namespace std;
const int N=5e5+20;
const int inf=0x3f3f3f3f;
struct node{
int ch[2],f,v;
}t[N];
int a,tmp,x1,x2,ans;
int n,root,tot;
void SC(int x,int y,int z)
{
t[x].ch[z]=y;
t[y].f=x;
}
bool d(int x){return t[t[x].f].ch[1]==x;}//x是左孩子还是右孩子.
void rot(int x)
{
int y=t[x].f,z=t[y].f,tt=d(x);
SC(z,x,d(y));
SC(y,t[x].ch[!tt],tt);
SC(x,y,!tt);
}
void splay(int x,int fa)
{
while(t[x].f!=fa)
{
if(t[t[x].f].f==fa)
{
rot(x);
break;
}
if(d(x)==d(t[x].f))
{
rot(t[x].f);
rot(x);
}
else
rot(x),rot(x);
}
}
int get(int x,int s)
{
int tmp=t[x].v;
while(x)
{
x=t[x].ch[s];
if(x==0||x==n+1)
break;
tmp=t[x].v;
}
return tmp;
}
void insert(int y)
{
if(!root)
{
root=++tot;
t[tot].v=y,t[tot].f=0;
return;
}
int x=root,z;
while(x)
{
z=x;
if(y<t[x].v)
x=t[x].ch[0];
else
x=t[x].ch[1];
}
if(y<t[z].v)
t[z].ch[0]=++tot;
else
t[z].ch[1]=++tot;
t[tot].v=y,t[tot].f=z;
splay(tot,0),root=tot;//
}
int main()
{
scanf("%d",&n);
scanf("%d",&ans);
t[0].v=t[n+1].v=inf;
insert(ans);
for(int i=2;i<=n;i++)
{
scanf("%d",&a);
insert(a);
x1=get(t[root].ch[0],1);
x2=get(t[root].ch[1],0);
int res=min(abs(a-x1),abs(a-x2));
ans+=res;
}
cout<<ans<<endl;
return 0;
}