3
27
2015
0

HNOI2002营业额统计

BZOJ1588: [HNOI2002]营业额统计
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

【分析见下,先奉上代码】

program turnover;
type
  tnode=record
    father,left,right:integer;
    data:longint;
  end;
var
  tree:array[0..32800] of tnode;
  root,now1,now,min,next,prev,n:longint;
  ans:int64;
procedure leftrotate(x:integer);
var
  y:integer;
begin
  y:=tree[x].father;
  tree[y].right:=tree[x].left;
  if tree[x].left <> 0 then
    tree[tree[x].left].father:=y;
  tree[x].father:=tree[y].father;
  if tree[y].father<>0 then
  begin
    if y=tree[tree[y].father].left
      then tree[tree[y].father].left:=x
      else tree[tree[y].father].right:=x;
  end;
  tree[y].father:=x;
  tree[x].left:=y;
end;
procedure rightrotate(x:integer);
var
  y:integer;
begin
  y:=tree[x].father;
  tree[y].left:=tree[x].right;
  if tree[x].right <> 0 then
    tree[tree[x].right].father:=y;
  tree[x].father:=tree[y].father;
  if tree[y].father<>0 then
  begin
    if y=tree[tree[y].father].left
      then tree[tree[y].father].left:=x
      else tree[tree[y].father].right:=x;
  end;
  tree[y].father:=x;
  tree[x].right:=y;
end;

procedure splay(now:integer);
var
  t:integer;
begin
  while tree[now].father<>0 do
  begin
    t:=tree[now].father;
    if tree[t].father=0 then                        
    begin
      if now=tree[t].left
        then {zig} rightrotate(now)
        else {zag} leftrotate(now);
      break;
    end;
    if now=tree[t].left               
      then begin
             if t=tree[tree[t].father].left     
             then begin
               rightrotate(t);
               rightrotate(now);
             end
             else begin                        
               rightrotate(now);
               leftrotate(now);
             end
           end
      else begin
             if t=tree[tree[t].father].right   
             then begin
               leftrotate(t);
               leftrotate(now);
             end
             else begin                         //zag zig
               leftrotate(now);
               rightrotate(now);
             end
           end;
  end;
  root:=now;
end;

procedure ins();
var
  t:integer;
begin
  t:=root;
  now1:=now;
  while true do
  begin
    if (tree[now].data=tree[t].data)then
    begin
      now1:=t;
      min:=0;                         
      exit;
    end;
    if (tree[t].data>tree[now].data)
    then begin
           if tree[t].left=0
           then begin
                  tree[now].father:=t;
                  tree[t].left:=now;
                  exit;
                end
           else t:=tree[t].left;
         end
    else begin
           if tree[t].right=0
           then begin
                  tree[now].father:=t;
                  tree[t].right:=now;
                  exit;
                end
           else t:=tree[t].right;
         end;
  end;
end;

procedure findprev;          
begin
  prev:=tree[now].left;
  while prev<>0 do
  begin
    if tree[prev].right=0 then exit;
    prev:=tree[prev].right;
  end;
end;

procedure findnext;         
begin
  next:=tree[now].right;
  while next<>0 do
  begin
    if tree[next].left=0 then exit;
    next:=tree[next].left;
  end;
end;

procedure work();
begin
  readln(tree[now].data);
  min:=maxint;
  ins();
  splay(now1);          
  if min>0 then
  begin
    findprev;
    findnext;
    if (next<>0)and((prev=0)or
      (tree[next].data-tree[now].data<tree[now].data-tree[prev].data))
    then min:=tree[next].data-tree[now].data
    else min:=tree[now].data-tree[prev].data;
  end;
  ans:=ans+min;
end;


begin
  fillchar(tree,sizeof(tree),0);
  readln(n);
  now:=1;
  readln(tree[1].data);
  root:=1;
  ans:=tree[1].data;
  for now:=2 to n do
    work;
  writeln(ans);
end.

RunID

User Problem Result Memory Time Language Code_Length Submit_Time
908799 Chuck__ 1588 Accepted 612 kb 232 ms Pascal/Edit 4181 B 2015-03-27 22:20:34
4k+的代码量有点大了。明天缩一缩,顺便再用线段树AC一次,在写个splay tree的详细内容

我来写下题目的【分析】
首先,这题是标准的SPLAY TREE模板题。
我今天花了一节体育课一节微机课和45分钟的睡觉时间搞定了splay tree
它算是一种二叉排序树,重点的操作在zig.zag上(zig zag到底是什么鬼单词!)
zig是右旋
zag是左旋
旋转的目的是为了把目标结点转换成根。这样就方便查找了。

如题,查找的内容是最小差值,
那么我们已知根(目前操作的数)
再从左子树里(比目前操作数要小的)中间找出最大的prev
从右子树里(比目前操作数要大的)中间找出最小的next。
再判断最小的差值min(now.data-prev.data,next.data-now.data)
操作完之后再插入时维护左边小右边大就行了。

语文差,勿吐槽。

 

Category: 日题 | Tags: HNOI 模板题 splay tree | Read Count: 341

登录 *


loading captcha image...
(输入验证码)
or Ctrl+Enter

Host by is-Programmer.com | Power by Chito 1.3.3 beta | Theme: Aeros 2.0 by TheBuckmaker.com