【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.