当前位置: 代码迷 >> 综合 >> [bzoj1588][Splay]营业额统计
  详细解决方案

[bzoj1588][Splay]营业额统计

热度:99   发布时间:2023-12-19 05:48:59.0

Description

营业额统计 Tiger最近被公司升任为营业部经理,他上任后接受公司交给的第一项任务便是统计并分析公司成立以来的营业情况。
Tiger拿出了公司的账本,账本上记录了公司成立以来每天的营业额。分析营业情况是一项相当复杂的工作。由于节假日,大减价或者是其他情况的时候,营业额会出现一定的波动,当然一定的波动是能够接受的,但是在某些时候营业额突变得很高或是很低,这就证明公司此时的经营状况出现了问题。经济管理学上定义了一种最小波动值来衡量这种情况:
该天的最小波动值 当最小波动值越大时,就说明营业情况越不稳定。
而分析整个公司的从成立到现在营业情况是否稳定,只需要把每一天的最小波动值加起来就可以了。你的任务就是编写一个程序帮助Tiger来计算这一个值。
第一天的最小波动值为第一天的营业额。 ? 输入输出要求

Input

第一行为正整数 ,表示该公司从成立一直到现在的天数,接下来的n行每行有一个整数(有可能有负数) ,表示第i 天公司的营业额。
天数n<=32767, 每天的营业额ai <= 1,000,000。 最后结果T<=2^31

Output

输出文件仅有一个正整数,即Sigma(每天最小的波动值) 。结果小于2^31 。

Sample Input

6
5
1
2
5
4
6

Sample Output

12

HINT

结果说明:5+|1-5|+|2-1|+|5-5|+|4-5|+|6-5|=5+4+1+0+1+1=12

该题数据bug已修复.—-2016.5.15

题解

我哭了我再也不装逼写01Tire了
写了一个晚上的01Tire,结果还是没过,发现数据有,有,有负数。。
超级想哭的
Splay就水啦直接找前驱后继。。
贴个模版挖个坑
以后强了再来写01Tire

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
struct trnode
{int d;//int n;//重复节点个数int c;//控制的人数int f;//父亲int son[2];//儿子
}tr[110000];int len;bool bk;
int root;//目前的皇帝 
void update(int x)
{int lc=tr[x].son[0],rc=tr[x].son[1];tr[x].c=tr[lc].c+tr[rc].c+tr[x].n;//自身控制的人数是  左孩子控制的人数  加上  右孩子控制的人数  再加上和  我同名的人数 
}
void add(int d,int f)//增加一个值为d的节点,作为f的儿子
{len++;tr[len].d=d; tr[len].n=1; tr[len].c=1;//目前只知道有一个重复的,一个控制的tr[len].f=f; if(d<tr[f].d) tr[f].son[0]=len; else tr[f].son[1]=len;//父亲为f,f也认他为儿子 tr[len].son[0]=tr[len].son[1]=0;//儿子暂时没有 
}
void rotate(int x,int w)//零左旋转 一右旋转 
{int f=tr[x].f,ff=tr[f].f;int R,r;//大R要成为父亲,小r要成为儿子 R=f; r=tr[x].son[w];tr[R].son[1-w]=r;//我爸爸的儿子设置为我原来的 if(r!=0) tr[r].f=R;R=ff; r=x;if(tr[R].son[0]==f) tr[R].son[0]=r; else tr[R].son[1]=r;tr[r].f=R;//然后把我自己设置为我原来爷爷的儿子 R=x; r=f;tr[R].son[w]=r;tr[r].f=R;update(f); update(x);
}
void splay(int x,int rt)//将x变成rt的其中一个儿子
{while(tr[x].f!=rt){int f=tr[x].f,ff=tr[f].f;if(ff==rt)//如果我祖父就是rt的话,那么只用旋转一次{if(tr[f].son[0]==x) rotate(x,1);else rotate(x,0);}else{if(tr[ff].son[0]==f && tr[f].son[0]==x){ rotate(f,1); rotate(x,1);}else if(tr[ff].son[1]==f && tr[f].son[1]==x){ rotate(f,0); rotate(x,0);}else if(tr[ff].son[0]==f && tr[f].son[1]==x){ rotate(x,0); rotate(x,1);}else if(tr[ff].son[1]==f && tr[f].son[0]==x){ rotate(x,1); rotate(x,0);}   }}if(rt==0) root=x;//如果我父亲就是上帝,那么我就是皇帝 
}
int findip(int d)//找值为 d 的节点
{int x=root;//从最顶端开始while(tr[x].d!=d){if(d<tr[x].d)//如果他小于tr[x].d(左边一定比tr[x].d小){if(tr[x].son[0]==0) break;//但是如果没有左孩子,那么就到底else x=tr[x].son[0]; }else{if(tr[x].son[1]==0) break;//同理,没有右孩子一样到底else x=tr[x].son[1]; }}return x;//这时候一定到了最接近的 
}
void ins(int d)
{if(root==0){add(d,0);root=len; return ;}int x=findip(d);//找最接近d的节点if(d==tr[x].d){bk=true;tr[x].n++;//同名的加一个update(x); splay(x,0);//把最近一个查找的变成根节点 }else{add(d,x);//那么把d作为x的儿子update(x);splay(len,0);//把len(  d  )变成根节点 }
}
void del(int d)
{int x=findip(d); splay(x,0);if(tr[x].n>1){
   tr[x].n--; update(x); return ;}//多一个的话,直接删除一个 if(tr[x].son[0]==0 && tr[x].son[1]==0) {root=0; len=0;}//如果都是0的话,那么直接删除树 else if(tr[x].son[0]==0 && tr[x].son[1]!=0){root=tr[x].son[1]; tr[root].f=0;}else if(tr[x].son[0]!=0 && tr[x].son[1]==0){root=tr[x].son[0]; tr[root].f=0;}else//都不为0 {int p=tr[x].son[0];while(tr[p].son[1]!=0)p=tr[p].son[1];splay(p,x);int R=p,r=tr[x].son[1];tr[R].son[1]=r;tr[r].f=R;root=R; tr[R].f=0;update(R);}
}
void findpaiming(int d)
{int x=findip(d); splay(x,0);printf("%d\n",tr[tr[x].son[0]].c+1);
}
void findshuzi(int k)
{int x=root;while(1){int lc=tr[x].son[0],rc=tr[x].son[1];if(k<=tr[lc].c) x=lc;else if(k>tr[lc].c+tr[x].n){k-=tr[lc].c+tr[x].n; x=rc;}else break;}splay(x,0);printf("%d\n",tr[x].d);
}
int findqianqu(int d)
{int x=findip(d); splay(x,0);if(d<=tr[x].d){x=tr[x].son[0];while(tr[x].son[1]!=0) x=tr[x].son[1];}return tr[x].d;
}
int findhouji(int d)
{int x=findip(d); splay(x,0);if(tr[x].d<=d){x=tr[x].son[1];while(tr[x].son[0]!=0) x=tr[x].son[0];}return tr[x].d;
}
int mymin(int x,int y){
   return x>y?y:x;}
int main()
{int n;int aa[21000];scanf("%d",&n);root=0; len=0;int ans=0;int x;for(int i=1;i<=n;i++){scanf("%d",&x);bk=false;ins(x);if(i==1) {ans+=x; continue;}else{if(bk==true){
   continue;}int kk=findqianqu(x),mm=findhouji(x);ans+=mymin(abs(x-kk),abs(x-mm));}}printf("%d\n",ans);return 0;
}

Wa的01Tire

#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#include<cmath>
using namespace std;
struct node
{int c[2],l,r;node(){c[0]=c[1]=-1;}
}tr[5110000];int rt,trlen;
int b[25],a[25],ln;
void get(int x)
{int len=0;int tmp=x;while(tmp){len++;//  if(x%2==1)b[ln]=1;//else b[ln]=0;tmp/=2;}tmp=x;ln=0;while(tmp){ln++;if(tmp%2==1)b[len-ln+1]=1;else b[len-ln+1]=0;tmp/=2;}memset(a,0,sizeof(a));for(int i=1;i<=ln;i++)a[i+23-ln]=b[i];
}
void add()
{int p=rt;for(int i=1;i<=23;i++){if(a[i]==0){
   tr[p].l++;if(tr[p].c[0]==-1)tr[p].c[0]=++trlen;p=tr[p].c[0];}else {
   tr[p].r++;if(tr[p].c[1]==-1)tr[p].c[1]=++trlen;p=tr[p].c[1];}}
}
int q[25];
int find_rk()
{int p=rt,ret=0;if(a[1]==0){if(tr[p].c[0]==-1)return 1;else p=tr[p].c[0];}if(a[1]==1){if(tr[p].c[1]==-1)return 1;else p=tr[p].c[1];}for(int i=1;i<=23;i++){if(a[i+1]==0){if(tr[p].c[0]==-1)break;p=tr[p].c[0];}else{ret+=tr[p].l;if(tr[p].c[1]==-1)break;p=tr[p].c[1];}}return ret+1;
}
int fd(int k)//排第k的数 
{int p=rt,sum=0,ret=0;for(int i=1;i<=23;i++){if(p==-1)break;if(sum+tr[p].l<k)sum+=tr[p].l,p=tr[p].c[1],ret+=(1<<(23-i));else p=tr[p].c[0];}
//  printf(" %d\n",ret);return ret;
}
int main()
{
//  freopen("turnover.IN4","r",stdin);int n,ans=0;scanf("%d",&n);rt=0;for(int i=1;i<=n;i++){int x;scanf("%d",&x);get(x);if(i==1)ans=x,add();else{int rk=find_rk();//if(rk>i)printf(" NO\n");//  printf(" %d\n",rk);int u=fd(rk-1),v=fd(rk);if(u==0)u=999999999;int tmp=min(abs(x-u),abs(x-v));if(rk<i)tmp=min(tmp,abs(x-fd(rk+1)));ans+=tmp;//printf(" %d\n",ans);add();}}printf("%d\n",ans);return 0;
}