【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.
原文地址:https://www.cnblogs.com/Delostik/p/1987397.html