现在的位置: 首页 > 综合 > 正文

bzoj 1588 [HNOI2002] 营业额统计

2014年04月05日 ⁄ 综合 ⁄ 共 2972字 ⁄ 字号 评论关闭

1588: [HNOI2002]营业额统计

Time Limit: 5 Sec  Memory Limit: 162 MB
Submit: 6942  Solved: 2292
[Submit][Status]

Description

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

Input

第一行为正整数 ,表示该公司从成立一直到现在的天数,接下来的n行每行有一个正整数 ,表示第i天公司的营业额。

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

序言:纪念我的第一道splay的题目~~~~~~~~~~~

简述题意:输入N天的营业额,求每天的营业最小波动值的和。第i天的营业最小波动值=min(abs(a[j]-a[i]))(1<=j<i)。

很容易想到n^2的暴力,当然也很容易发现不行。于是不知不觉就想到了BST。但是数据会卡啊。如果全都是一模一样的数字,或者是递减、递增,BST和n^2也差不了多少!

于是,我们的splay横空出世!在前段时间我已经研究了它的基本概念,现在开始敲代码。

首先要明确一点:如何求某一天的最小波动值。设该点时A,在插入到BST后,我们先把这个顶点调到根节点。那么在它的左子树中,所有值都比它小;我们要使比它小的值尽量大,就要不断往左子树中的右结点中找一个值X。同理,在它的右子树中,所有值都比它大;我们要使比它大的值尽量小,就要不断往右子树中的左结点中找一个值Y。那么,该A点的最小波动值=min(A-X,Y-X)。再开个累加器即可。

以下是代码:

#include<stdio.h>
#include<cmath>
using namespace std;
const int maxn=40001;
const int oo=2100000000;
int father[maxn],left[maxn],right[maxn],num[maxn];  //num[i]表示第i天的营业额。
int n,a,i,lef,righ,root;
long long ans;
int min(int a,int b)                     
{
  if (a<b) return a;
  return b;
}
void left_up(int x)                             //zig——左旋
{
  int y=father[x];right[y]=left[x];
  if (left[x]!=0) father[left[x]]=y;
  int fa=father[y];
  father[x]=fa;
  if (fa!=0) 
  {
    if (left[fa]==y) left[fa]=x;else right[fa]=x;
  }
  father[y]=x;left[x]=y;
}
void right_up(int x)                         //zag——右旋
{
  int y=father[x];left[y]=right[x];
  if (right[x]!=0) father[right[x]]=y;
  int fa=father[y];
  father[x]=fa;
  if (fa!=0)
  {
    if (left[fa]==y) left[fa]=x;else right[fa]=x;
  }
  father[y]=x;right[x]=y;
}
void splay(int x)                          //把x结点旋转到根节点。
{
  while (father[x]!=0)
  {
    int y=father[x];
    if (father[y]==0)
    {
      if (x==left[y]) right_up(x);else left_up(x);
      break;
    }
    int fa=father[y];
    if (x==left[y])
    {
      if (y==left[fa]){right_up(y);right_up(x);}
      else {right_up(x);left_up(x);}
    }
    else
    {
      if (y==right[fa]) {left_up(y);left_up(x);}
      else {left_up(x);right_up(x);}
    }
  }
  root=x;
}
void insert(int k)                      //把k结点插到BST里。
{
  if (a<num[k])
  {
    if (left[k]==0)
    {
      left[k]=i;
      father[i]=k;
      num[i]=a;
    }
    else insert(left[k]);
  }
  else
  {
    if (right[k]==0)
    {
      right[k]=i;
      father[i]=k;
      num[i]=a;
    }
    else insert(right[k]);
  }
}
int search_1(int k)                       //找左节点
{
  if (left[k]!=0) return search_1(left[k]);
  else return num[k];
}
int search_2(int k)                   //找右结点
{
  if (right[k]!=0) return search_2(right[k]);
  else return num[k];
}
int main()
{
  scanf("%ld",&n);
  scanf("%ld",&a);
  father[1]=0;left[1]=0;right[1]=0;num[1]=a;ans=a;root=1;
  for (i=2;i<=n;i++)
  {
    if (scanf("%ld",&a)==EOF) a=0;
    insert(root);splay(i);
    int lef=left[root]!=0?search_2(left[root]):-oo;
    int righ=right[root]!=0?search_1(right[root]):oo;
    if (lef==-oo) ans+=righ-a;else if (righ==oo) ans+=a-lef;else ans+=min(a-lef,righ-a);
  }
  printf("%lld",ans);
  return 0;
}

抱歉!评论已关闭.