题目链接:https://loj.ac/problem/10143
解题思路
Treap模板题,我们发现对于每次ai,只需要找当前序列中比其大的最小的那个,和比其小的最大的那个,然后取差值的最小值加上去即可。所以需要用到Treap的插入,找前驱和后继即可。如果有相同元素,不受影响,不需要再插入了。之后套模板即可。
AC代码
#include <iostream>
#include <stdio.h>
#include <cstring>
#include <algorithm>
using namespace std;
int tot,rt;
const int N=(1<<15)+5;
const int inf=0x3f3f3f3f;
struct node
{
int lc,rc,fa,pos,vis;
#define lc(x) t[x].lc
#define rc(x) t[x].rc
#define fa(x) t[x].fa
#define pos(x) t[x].pos //pos(x)为x的优先级
#define vis(x) t[x].vis
}t[N];
inline void Zig(int &x)//右旋
{
int y=lc(x);
lc(x)=rc(y),rc(y)=x;
x=y;
}
inline void Zag(int &x)//左旋
{
int y=rc(x);
rc(x)=lc(y),lc(y)=x;
x=y;
}
inline void Insert(int &x,const int vi)//插入新元素
{
if(!x)
{
vis(x=++tot)=vi,pos(x)=rand();
return ;
}
if(vi<vis(x))
{
Insert(lc(x),vi);
if(pos(lc(x))<pos(x))
Zig(x);
}
else
{
Insert(rc(x),vi);
if(pos(rc(x))<pos(x))
Zag(x);
}
}
inline int QueryPre(const int vi)//求前驱
{
int x=rt,pr=-inf;
while(x)
{
if(vi>=vis(x))
pr=vis(x),x=rc(x);
else
x=lc(x);
}
return pr;
}
inline int QuerySuf(const int vi)//求后继
{
int x=rt,sf=inf;
while(x)
{
if(vi<=vis(x))
sf=vis(x),x=lc(x);
else
x=rc(x);
}
return sf;
}
inline int get()//读入优化
{
char c;
int sign=1;
while((c=getchar())<'0'||c>'9')//c=getchar()每次读入一个字符
if(c=='-')sign=-1;//判断是否出现负数情况
int res=c-'0';
while((c=getchar())>='0'&&c<='9')
res=res*10+c-'0';
return res*sign;
}
/*void dfs(int x)
{
if(x)
cout<<x<<" "<<vis(x)<<endl;
if(lc(x))
dfs(lc(x));
if(rc(x))
dfs(rc(x));
}
*/
int main()
{
int n,k,x,y,ans;
n=get();
//cout<<n<<endl;
Insert(rt,ans=get());
//cout<<"ans "<<ans<<endl;
while(--n)
{
k=get();
x=QueryPre(k);
y=QuerySuf(k);
ans+=min(k-x,y-k);
//cout<<"k x y "<<k<<" "<<x<<" "<<y<<endl;
//cout<<"ans "<<ans<<endl;
Insert(rt,k);
}
//dfs(1);
printf("%d\n",ans);
return 0;
}