题目链接
题目大意
输入
n
个数(
分析
我写的第一道Splay的题,基本就是对着大神的模板写。
每读入一个数就插入到伸展树中,然后将它旋转到根结点。跟它相差最小的点就是此时左子树中的最右边点和右子树中最左边点,映射到线性有序数组就是它的前驱结点和后驱结点。
代码
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <queue>
#define ls (rt<<1)
#define rs (rt<<1|1)
using namespace std;
const double pi=4*atan(1.0);
const int MAXN=100010;
const int MAXM=2*MAXN;
struct SplayTree
{
int root,tot;///根节点、结点数量
int nt[MAXN][2],pre[MAXN],val[MAXN];
///分别表示左右孩子(0左1右)、父节点、键值
void Init() {root=tot=0;}
void Newnode(int &rt,int father,int value) ///新建一个结点
{
rt=++tot;
nt[rt][0]=nt[rt][1]=0;
pre[rt]=father;
val[rt]=value;
}
void Rotate(int x,int kind)///旋转:kind 0为左旋,1为右旋
{
int y=pre[x];
nt[y][!kind]=nt[x][kind];
pre[nt[x][kind]]=y;
if (pre[y])
{
nt[pre[y]][nt[pre[y]][1]==y]=x;
}
pre[x]=pre[y];
nt[x][kind]=y;
pre[y]=x;
}
void Splay(int x,int goal)///Splay调整:将结点x调整到goal下面
{
while (pre[x]!=goal)
{
if (pre[pre[x]]==goal) ///单旋情况
Rotate(x,nt[pre[x]][0]==x);
else
{
int y=pre[x];
int kind=nt[pre[y]][0]==y;
if (nt[y][kind]==x) ///之字型旋转
{
Rotate(x,!kind);
Rotate(x,kind);
}
else ///一字型旋转
{
Rotate(y,kind);
Rotate(x,kind);
}
}
}
if (!goal) root=x;
}
bool Insert(int k)
{
int rt=root;
while (nt[rt][val[rt]<k])
{
if (val[rt]==k)///如果本身存在这个元素,只需把它调整到根节点即可
{
Splay(rt,0);
return false;
}
rt=nt[rt][val[rt]<k];
}
Newnode(nt[rt][val[rt]<k],rt,k); ///不存在这个元素就新插入这个元素
Splay(nt[rt][val[rt]<k],0);
return true;
}
int get_pre(int rt)///找rt结点的前驱结点 即左子树中最右边的结点
{
int x=nt[rt][0];
while (x)
{
while (nt[x][1])
x=nt[x][1];
return val[x];
}
return -1;
}
int get_next(int rt)///找rt结点的后继结点 即右子树中最左边的结点
{
int x=nt[rt][1];
while (x)
{
while (nt[x][0])
x=nt[x][0];
return val[x];
}
return -1;
}
};
SplayTree tree;
int main()
{
ios::sync_with_stdio(false);
int i,ans,num,n;
//freopen("in.txt","r",stdin);
while (scanf("%d",&n)!=EOF)
{
tree.Init();
ans=0;
for (i=1;i<=n;i++)
{
scanf("%d",&num);
if (i==1)
{
ans+=num;
tree.Newnode(tree.root,0,num);
continue;
}
if (!tree.Insert(num)) continue;
int a=tree.get_pre(tree.root);
int b=tree.get_next(tree.root);
if (a==-1) ans+=abs(num-b); ///要注意前继
else if (b==-1) ans+=abs(num-a);
else
ans+=min(abs(num-b),abs(num-a));
}
printf("%d\n",ans);
}
return 0;
}