[HNOI2002]营业额统计(SplayTree)
http://www.lydsy.com/JudgeOnline/problem.php?id=1588
题意:给你n个数,要你求出每个数的最小波动值之和.第一个数的波动值就是自己,之后第i个数的最小波动值=|val[i]-x|.其中x是与val[i]之差绝对值最小的之前出现过的数.
分析:
构建一个SplayTree,支持插入节点,找前驱和后继的值.当然还要支持单点插入操作,不过这颗SplayTree是一个排序二叉树,即关键字从小到大排序,这样才能找到前驱和后继.
AC代码: 注意代码中注释掉的那一段
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn=100000+100;
const int INF=0x3f3f3f3f;
struct SplayTree
{
int ch[maxn][2],pre[maxn],size[maxn],key[maxn],root,tot1;
void Rotate(int x,int kind)
{
int y=pre[x];
ch[y][kind^1]=ch[x][kind];
pre[ch[x][kind]]=y;
if(pre[y]) ch[pre[y]][ch[pre[y]][1]==y] = x;
pre[x]=pre[y];
ch[x][kind]=y;
pre[y]=x;
}
void Splay(int r,int goal)
{
while(pre[r]!=goal)
{
if(pre[pre[r]]==goal)
Rotate(r,ch[pre[r]][0]==r);
else
{
int y=pre[r];
int kind= ch[pre[y]][0]==y;
if(ch[y][kind]==r)
{
Rotate(r,kind^1);
Rotate(r,kind);
}
else
{
Rotate(y,kind);
Rotate(r,kind);
}
}
}
if(goal==0) root=r;
}
void NewNode(int &r,int fa,int k)
{
r=++tot1;
size[r]=1;
key[r]=k;
pre[r]=fa;
ch[r][0]=ch[r][1]=0;
}
int insert(int k)//无缺陷的insert
{
int r=root;
while(1)
{
if(key[r]==k)
{
Splay(r,0);
return 0;
}
else if(k<key[r])
{
if(ch[r][0]) r=ch[r][0];
else
{
NewNode(ch[r][0],r,k);
Splay(ch[r][0],0);
return 1;
}
}
else if(k>key[r])
{
if(ch[r][1]) r=ch[r][1];
else
{
NewNode(ch[r][1],r,k);
Splay(ch[r][1],0);
return 1;
}
}
}
}
/*有缺陷的insert(虽然也能AC),当输入为2 5 5 的时候,会在SplayTree中插入两个5
int insert(int k)
{
int r=root;
while(ch[r][key[r]<k])
{
if(key[r]==k)
{
Splay(r,0);
return 0;
}
r=ch[r][key[r]<k];
}
NewNode(ch[r][key[r]<k],r,k);
Splay(ch[r][key[r]<k],0);
return 1;
}
*/
int get_pre(int x)
{
int r=ch[x][0];
if(r==0) return INF;
while(ch[r][1]) r=ch[r][1];
return key[x]-key[r];
}
int get_next(int x)
{
int r=ch[x][1];
if(r==0) return INF;
while(ch[r][0]) r=ch[r][0];
return key[r]-key[x];
}
}st;
int main()
{
int n;
while(scanf("%d",&n)==1)
{
st.root=st.tot1=0;
int ans=0;
for(int i=1;i<=n;i++)
{
//printf("%d\n",st.tot1);
int num;
if(scanf("%d",&num)==EOF) num=0;
if(i==1) {ans+=num; st.NewNode(st.root,0,num); continue;}
if(st.insert(num)==0) continue;//这步已经把num旋转到了root
int a=st.get_pre(st.root);
int b=st.get_next(st.root);
ans+= min(a,b);
}
printf("%d\n",ans);
}
}