【HNOI 2002】营业额统计

  我发现这道题被各路神牛广泛地作为数据结构的初级模板练手题……也许是这个题可用的数据结构真的太多,线段树、平衡树、伸展树都可以AC。今天我使用了三种实现方法写这个题,目的就是练手……

  本人弱菜,神牛勿BS……

 题目:http://61.187.179.132:8080/JudgeOnline/showproblem?problem_id=1588

[HNOI2002]营业额统计

Time Limit:5000MS  Memory Limit:165536K
Total Submit:1139 Accepted:309
Case Time Limit:1000MS

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

  首先是比较简单的线段树解法。虽然题目中有明显的插入操作,但是我们可以注意到数据的量是一定的,线段树中数据个数为n,而且初始状态线段树中没有数据。那么我们可以预先开一个1..n的线段树,数据域初始为0,那么每次的插入操作就变成了修改第i个值。每次修改维护一下区间的最大值就可以了。

  (抱歉,线段树的代码不小心被我抹掉了……)

  第二种方法可以使用SBT。

{

Tag:营业额统计 HNOI_2002

Method:Size Balanced Tree

}

var key,size,left,right:array[0..40000]of longint;

    i,n,x,ans,total,root:longint;



procedure Left_Rotate(var x:longint);

var y:longint;

begin

  y:=right[x];

  right[x]:=left[y];

  left[y]:=x;

  size[y]:=size[x];

  size[x]:=size[left[x]]+size[right[x]]+1;

  x:=y;

end;



procedure Right_Rotate(var x:longint);

var y:longint;

begin

  y:=left[x];

  left[x]:=right[y];

  right[y]:=x;

  size[y]:=size[x];

  size[x]:=size[left[x]]+size[right[x]]+1;

  x:=y;

end;



procedure maintain(var x:longint;flag:boolean);

begin

  if flag then

    begin

      if size[left[left[x]]]>size[right[x]] then Right_Rotate(x)

        else if size[right[left[x]]]>size[right[x]] then

          begin

            Left_Rotate(left[x]);Right_Rotate(x);

          end

        else exit

   end

  else

    begin

      if size[right[right[x]]]>size[left[x]] then Left_Rotate(x)

        else if size[left[right[x]]]>size[left[x]] then

          begin

            Right_Rotate(right[x]);Left_Rotate(x);

          end

        else exit;

    end;

  maintain(left[x],true);

  maintain(right[x],true);

  maintain(x,true);

  maintain(x,false);

end;



procedure insert(var x:longint;data:longint);

begin

  if x=0 then

    begin

      inc(total);

      x:=total;

      size[x]:=1;

      left[x]:=0;

      right[x]:=0;

      key[x]:=data;

    end

  else

    begin

      inc(size[x]);

      if data<=key[x] then insert(left[x],data)

        else insert(right[x],data);

      maintain(x,data<=key[x]);

    end;

end;



function find(var x:longint;data:longint):longint;

begin

  if key[x]=data then exit(data);

  if data<key[x] then

    begin

      if left[x]=0 then find:=key[x] else find:=find(left[x],data)

    end

  else

    begin

      if right[x]=0 then find:=key[x] else find:=find(right[x],data);

    end;

  if abs(find-data)>abs(key[x]-data) then exit(key[x]);

end;



function min(a,b:longint):longint;

begin

  if a<b then exit(a);

  exit(b);

end;



begin

  total:=0;size[0]:=0;root:=0;

  readln(n);

  readln(x);

  insert(root,x);

  inc(ans,x);

  for i:=2 to n do

    begin

      readln(x);

      inc(ans,abs(find(root,x)-x));

      insert(root,x);

    end;

  writeln(ans);

  readln;readln;

end.

  第三种方法:Splay

{

Tag:HNOI_2002 营业额统计

Method:Splay

}

program HNOI_2002_Count;

type rec=record

               lch,rch,father,data:longint;

     end;



var tree:array[0..80000]of rec;

    n,ans,i,x,root,total,a,b:longint;



function min(a,b:longint):longint;

begin

  if a<b then exit(a);

  exit(b);

end;



procedure Left_Rotate(var x:longint);

var y,fa:longint;

begin

  y:=tree[x].lch;fa:=tree[x].father;

  if x=tree[fa].lch then tree[fa].lch:=y

    else tree[fa].rch:=y;

  tree[y].father:=fa;

  tree[x].lch:=tree[y].rch;

  tree[tree[y].rch].father:=x;

  tree[y].rch:=x;

  tree[x].father:=y;

  x:=y;

end;



procedure Right_Rotate(var x:longint);

var y,fa:longint;

begin

  y:=tree[x].rch;fa:=tree[x].father;

  if x=tree[fa].lch then tree[fa].lch:=y

    else tree[fa].rch:=y;

  tree[y].father:=fa;

  tree[x].rch:=tree[y].lch;

  tree[tree[y].lch].father:=x;

  tree[y].lch:=x;

  tree[x].father:=y;

  x:=y;

end;



procedure splay(x:longint);

var y,z:longint;

begin

  while tree[x].father<>0 do

    begin

      y:=tree[x].father;

      if tree[y].father=0 then

        begin

          if x=tree[y].lch then Left_Rotate(y)

            else Right_Rotate(y);

        end

      else

        begin

          z:=tree[y].father;

          if y=tree[z].lch then

            begin

              if x=tree[y].lch then

                begin

                  Left_Rotate(z);

                  Left_Rotate(z);

                end

              else

                begin

                  Right_Rotate(y);

                  Left_Rotate(z);

                end;

              end

          else

            begin

              if x=tree[y].rch then

                begin

                  Right_Rotate(z);

                  Right_Rotate(z);

                end

              else

                begin

                  Left_Rotate(y);

                  Right_Rotate(z);

                end;

            end;

        end;

    end;

  root:=x;

end;



procedure insert(x,data:longint);

begin

  while true do

    begin

      if data>tree[x].data then

        begin

          if tree[x].rch=0 then

            begin

              inc(total);

              tree[total].data:=data;

              tree[x].rch:=total;

              tree[total].father:=x;

              splay(total);

              exit;

            end

          else x:=tree[x].rch;

        end

      else

        begin

          if tree[x].lch=0 then

            begin

              inc(total);

              tree[total].data:=data;

              tree[x].lch:=total;

              tree[total].father:=x;

              splay(total);

              exit;

            end

          else x:=tree[x].lch;

        end;

    end;

end;



function pred(x:longint):longint;

begin

  if x=0 then exit(maxlongint);

  while tree[x].rch<>0 do x:=tree[x].rch;

  exit(tree[x].data);

end;



function succ(x:longint):longint;

begin

  if x=0 then exit(maxlongint);

  while tree[x].lch<>0 do x:=tree[x].lch;

  exit(tree[x].data);

end;



begin

  readln(n);

  total:=3;root:=1;ans:=0;

  readln(x);

  inc(ans,x);

  tree[1].father:=0;

  tree[1].data:=x;

  tree[1].lch:=2;

  tree[1].rch:=3;

  tree[2].father:=1;

  tree[2].data:=-maxlongint div 2;

  tree[3].father:=1;

  tree[3].data:=maxlongint div 2;

  for i:=2 to n do

    begin

      readln(x);

      insert(root,x);

      a:=pred(tree[root].lch);

      b:=succ(tree[root].rch);

      ans:=ans+min(abs(x-a),abs(x-b));

    end;

  writeln(ans);

  readln;readln;

end.

你可能感兴趣的:(统计)