splay入门题。。将n个数依次插入,查询第i个数之前的数中它的前缀和后缀,选择delta小的更新答案即可。。注意无前(后)缀或者有相等的情况。。
很久以前的代码:
#include<iostream>
#include<cstdio>
#include<memory.h>
using namespace std;
const int MAX=999999999;
int pre[100010],c[100010][3],num[100010],i,n,q,ans=0,sumn,root=0,pren,nextn;
void newnode(int &x,int fa,int k)
{x=++sumn;
pre[x]=fa;
num[x]=k;
c[x][0]=c[x][1]=0;
}
void rotate(int x,int rk)
{int y=pre[x],z=pre[y];
pre[x]=z;pre[y]=x;
c[y][!rk]=c[x][rk];
pre[c[x][rk]]=y;
c[x][rk]=y;
if (z!=0) c[z][c[z][1]==y]=x;
}
void splay(int r,int goal)
{
while(pre[r]!=goal)
{
if(pre[pre[r]]==goal) rotate(r,c[pre[r]][0]==r);
else
{
int y=pre[r];
int kind=c[pre[y]][0]==y;
if(c[y][kind]==r)
{
rotate(r,!kind);
rotate(r,kind);
}
else
{
rotate(y,kind);
rotate(r,kind);
}
}
}
//更新根结点
if(goal==0)root=r;
}
int insert(int k)
{int get=root;
while (c[get][num[get]<k])
{if (num[get]==k)
{splay(get,0);
return 0;
}
get=c[get][num[get]<k];
}
newnode(c[get][num[get]<k],get,k);
splay(c[get][num[get]<k],0);
return 1;
}
int getpre(int x)
{int r=c[x][0];
if (r==0) return MAX;
while (c[r][1]) r=c[r][1];
return num[x]-num[r];
}
int getnext(int x)
{int r=c[x][1];
if (r==0) return MAX;
while (c[r][0]) r=c[r][0];
return num[r]-num[x];
}
int main()
{freopen("splay.in","r",stdin);
//freopen("my.out","w",stdout);
scanf("%d",&n);
for (i=1;i<=n;i++)
{if (scanf("%d",&q)==EOF) q=0;
if (i==1)
{ans+=q;
newnode(root,0,q);
//printf("%d\n",ans);
continue;
}
if (insert(q)==0) continue;
pren=getpre(root);
nextn=getnext(root);
ans+=min(pren,nextn);
//printf("%d\n",ans);
}
printf("%d\n",ans);
fclose(stdin);
//fclose(stdout);
}