bzoj 1588 //1588: [HNOI2002]营业额统计 //在线测评地址https://www.lydsy.com/JudgeOnline/problem.php?id=1588
//在线测评地址https://www.luogu.org/problem/P2234
更多题解,详见https://blog.csdn.net/mrcrack/article/details/90228694BZOJ刷题记录
Splay入门,详见此文https://blog.csdn.net/mrcrack/article/details/103196131
Accepted | 1468 kb | 228 ms | C++/Edit | 3623 B |
//1588: [HNOI2002]营业额统计
//在线测评地址https://www.lydsy.com/JudgeOnline/problem.php?id=1588
//在线测评地址https://www.luogu.org/problem/P2234
//有了结果说明,题意还是好理解的。2019-11-17 20:37
//O(n^2)算法肯定超时。
//splay感觉细节挺多的,靠看,很难掌握,靠理解,细节太多,还是开始编码吧,在编码的过程中进行体会,一遍不行,两遍吧。
//也不再固执,用上C++类的特性吧。2019-11-26
#include
using namespace std;
#define maxn 32867//32767+100
#define INF 1e7//因1e6-0=1e6,这是最大差值,故1e7足够用了
int cnt=0;//cnt记录节点插入树中的时间顺序。
struct Splay_Tree{
int rt;//根节点,记录节点的时间戳。
int val[maxn],size[maxn],fa[maxn],ch[maxn][2];//一个节点需要具备的信息,值,所含节点数(包括自己),父亲是谁,孩子是谁。ch[][0]左孩子,ch[][1]右孩子,如何确定节点,靠时间戳。
int max(int a,int b){
return a>b?a:b;
}
int min(int a,int b){
return a }
void insert(int v){//插入节点值
int pos,posfa,f;//此处错写成int pos,posfa;//posfa记录pos的父亲
if(++cnt!=1){//插入的节点不是第1个点。
pos=rt;//按二叉查找树的方式插入
while(size[pos]){//一定要找到底,到底,size[]为0,找到该节点插入位置;从何处找起,确定一棵树的起始,当然是根。
if(v<=val[pos])posfa=pos,pos=ch[pos][0],f=0;//此处错写成if(v<=val[pos])posfa=pos,pos=ch[pos][0];//左树
else posfa=pos,pos=ch[pos][1],f=1;//此处错写成else posfa=pos,pos=ch[pos][1];//右树
}
fa[cnt]=posfa,size[cnt]=1,val[cnt]=v,ch[posfa][f]=cnt;//此处错写成fa[pos]=posfa,size[pos]=1,val[pos]=v;//只要找父亲,及确定自己的值即可,没有孩子。
splay(cnt,0);//平衡树 将v拧到树根。
}else val[cnt]=v,size[cnt]=1,rt=cnt;//第一个节点插入树中。
}
int Query(int v){
int pos=rt,Pre,Nex;
while(size[pos]){//此处错写成while(1){
if(v
else if(v>val[pos])Pre=val[pos],pos=ch[pos][1];//此处错写成else if(v>val[pos])pos=ch[pos][1],Pre=val[pos];
}
return min(Nex-v,v-Pre);
}
void splay(int x,int pos){//写在struct里的好处是,不用注意函数的前后顺序了
int y,z,f1,f2;
for(y=fa[x],z=fa[y];y!=pos;y=fa[x],z=fa[y]){//此处错写成for(y=fa[x],z=fa[y];pos;x=fa[y],y=fa[z]){//自x处开始拧
f1=ch[y][1]==x,f2=ch[z][1]==y;
if(z==pos)rotate(x,f1);//无爷爷
else if(f1^f2)rotate(x,f1),rotate(x,f2);//子父,父爷 连线不共线 拧2次x
else rotate(y,f2),rotate(x,f1);//子父,父爷 连线 共线 先拧y,再拧x
}
update(x);//漏了此句
if(pos==0)rt=x;//任命x为新的根
}
void rotate(int x,int f){
int y=fa[x],z=fa[y],u=ch[x][f^1];
if(z)ch[z][ch[z][1]==y]=x;//此处错写成fa[x]=z,ch[z][ch[z][1]==y]=x,update(z);//处理x与原爷爷的关系,挂y的地方,挂上x
fa[x]=z;//此处写错了位置
fa[y]=x,ch[x][f^1]=y;//此处错写成fa[y]=x,ch[x][f^1]=y,update(x);//处理x与原父亲的关系,挂u的地方,挂上y
fa[u]=y,ch[y][ch[y][1]==x]=u,update(y);//此处错写成fa[u]=y,ch[y][ch[y][1]==x]=u,update(y);//处理x的子u与原x父亲的关系,挂x的地方,挂上u。
}
void update(int x){
size[x]=size[ch[x][0]]+size[ch[x][1]]+1;
}
}Tree;
int main(){
int sum=0,n,Val,i;
scanf("%d",&n);
Tree.insert(INF);//因查找过程中,一定要找到一个后继,故手动插入最大值
Tree.insert(-INF);//因查找过程中,一定要找到一个前驱,故手动插入最小值
for(i=1;i<=n;i++){
scanf("%d",&Val);
if(i==1)sum+=Val;
else sum+=Tree.Query(Val);
Tree.insert(Val);//别忘了,插入该节点
}
printf("%d\n",sum);
return 0;
}