BZOJ1588: [HNOI2002]营业额统计
Posted Star_Feel
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了BZOJ1588: [HNOI2002]营业额统计相关的知识,希望对你有一定的参考价值。
【传送门:BZOJ1588】
简要题意:
给出n个数,每个数只能前面的任意一个数相减,要求差的绝对值最小,求出所有数做的差的最小绝对值的和(第一个数做得差的最小绝对值就是它自己)
题解:
伸展树SPLAY,将n个数逐个放进伸展树中,在放一个数时,先求出这个数在树中的前驱和后继,然后比较哪个最接近这个数,然后ans加上前驱或后继与这个数的差的绝对值,然后把这个数放进伸展树里
参考代码:
#include<cstdio> #include<cstring> #include<cstdlib> #include<algorithm> #include<cmath> using namespace std; struct node { int n,d,f,c,son[2]; }a[110000];int len,root; void add(int d,int f) { len++; a[len].d=d;a[len].c=a[len].n=1; a[len].son[1]=a[len].son[0]=0;a[len].f=f; if(d<a[f].d) a[f].son[0]=len; else a[f].son[1]=len; } void update(int x) { int lc=a[x].son[0],rc=a[x].son[1]; a[x].c=a[x].n+a[lc].c+a[rc].c; } int findip(int d) { int x=root; while(a[x].d!=d) { if(a[x].d>d) { if(a[x].son[0]==0)break; else x=a[x].son[0]; } else { if(a[x].son[1]==0)break; else x=a[x].son[1]; } } return x; } void rotate(int x,int w) { int f=a[x].f,ff=a[f].f; int r,R; r=a[x].son[w];R=f; a[R].son[1-w]=r; if(r!=0)a[r].f=R; r=x;R=ff; if(a[R].son[0]==f)a[R].son[0]=r; else a[R].son[1]=r; a[r].f=R; r=f;R=x; a[R].son[w]=r; a[r].f=R; update(f); update(x); } void splay(int x,int rt) { while(a[x].f!=rt) { int f=a[x].f,ff=a[f].f; if(ff==rt) { if(a[f].son[0]==x)rotate(x,1); else rotate(x,0); } else { if(a[f].son[0]==x && a[ff].son[0]==f){rotate(f,1);rotate(x,1);} else if(a[f].son[1]==x && a[ff].son[0]==f){rotate(x,0);rotate(x,1);} else if(a[f].son[0]==x && a[ff].son[1]==f){rotate(x,1);rotate(x,0);} else if(a[f].son[1]==x && a[ff].son[1]==f){rotate(f,0);rotate(x,0);} } } if(rt==0)root=x; } void ins(int d) { if(root==0) { add(d,0);root=len; return ; } int x=findip(d); if(d==a[x].d) { a[x].n++; update(x); splay(x,0); } else { add(d,x); update(x); splay(len,0); } } void del(int d) { int x=findip(d);splay(x,0); if(d!=a[x].d)return ; if(a[x].n>1){a[x].n--;update(x);return ;} if(a[x].son[0]==0 && a[x].son[1]==0){root=0;len=0;} else if(a[x].son[0]!=0 && a[x].son[1]==0){root=a[x].son[0];a[root].f=0;} else if(a[x].son[1]!=0 && a[x].son[0]==0){root=a[x].son[1];a[root].f=0;} else { int p=a[x].son[0]; while(a[p].son[1]!=0)p=a[p].son[1]; splay(p,x); int r,R; r=a[x].son[1];R=p; a[R].son[1]=r; a[r].f=R; root=R;a[root].f=0; update(R); } } int findqianqu(int d) { int x=findip(d);splay(x,0); if(d<a[x].d && a[x].son[0]!=0) { x=a[x].son[0]; while(a[x].son[1]!=0)x=a[x].son[1]; } if(d<a[x].d)x=0; return x; } int findhouji(int d) { int x=findip(d);splay(x,0); if(d>a[x].d && a[x].son[1]!=0) { x=a[x].son[1]; while(a[x].son[0]!=0)x=a[x].son[0]; } if(d>a[x].d)x=0; return x; } int findpaiming(int d) { int x=findip(d); splay(x,0); return a[a[x].son[0]].c+1; } int findshuzi(int k) { int x=root; while(1) { int lc=a[x].son[0],rc=a[x].son[1]; if(k<=a[lc].c)x=lc; else if(k>a[lc].c+a[x].n){k-=a[lc].c+a[x].n;x=rc;} else break; } return a[x].d; } int n; int main() { scanf("%d",&n);len=0;root=0; int ans=0;int d; scanf("%d",&d);ans+=d;ins(d); for(int i=2;i<=n;i++) { scanf("%d",&d); int ss=999999999; int lc=findqianqu(d),rc=findhouji(d); if(lc!=0) ss=abs(a[lc].d-d); if(rc!=0) ss=min(abs(a[rc].d-d),ss); ans+=ss; ins(d); } printf("%d\n",ans); return 0; }
以上是关于BZOJ1588: [HNOI2002]营业额统计的主要内容,如果未能解决你的问题,请参考以下文章
bzoj 1588: [HNOI2002]营业额统计 treap