AVL平衡树裸题(营业额统计)

来源:互联网 发布:仁和知柏地黄丸怎么样 编辑:程序博客网 时间:2024/06/03 13:19

问题 A(2805): 营业额统计

时间限制: 1 Sec  内存限制: 128 MB提交: 254  解决: 119

题目描述

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

输入

第一行为正整数 ,表示该公司从成立一直到现在的天数

接下来的n行每行有一个整数(一定有数据小于〇) ,表示第i天公司的营业额。

输出

输出文件仅有一个正整数,即每一天的最小波动值之和。答案保证在int范围内。

样例输入

 (如果复制到控制台无换行,可以先粘贴到文本编辑器,再复制)

6512546

样例输出

12

提示

结果说明:5+|1-5|+|2-1|+|5-5|+|4-5|+|6-5|=5+4+1+0+1+1=12





这道题就是道平衡树裸题,思路上没什么好说的,就是平衡树

稍微难点的是如何找到那个最小波动值

而代码实现较困难,很多细节很多坑,所以着重解释代码


AC代码如下:


#include<iostream> #include<cstdio> #include<algorithm> #include<climits>    const int MAXN=100000; using namespace std; struct node{int rc,lc,h,data;}tree[MAXN+5]; int n,t1,root,ans,cnt,M;    inline void Get_int(int &Ret){     char ch;     bool flag=0;     for(;ch=getchar(),ch<'0'||ch>'9';)if(ch=='-') flag=1;     for(Ret=ch-'0';ch=getchar(),ch>='0'&&ch<='9';Ret=Ret*10+ch-'0');     flag&&(Ret=-Ret); } inline int zig(int i){     int t=tree[i].lc;     tree[i].lc=tree[t].rc;     tree[t].rc=i;     tree[i].h=max(tree[tree[i].lc].h,tree[tree[i].rc].h)+1;     tree[t].h=max(tree[tree[t].lc].h,tree[tree[t].rc].h)+1;     return t; } inline int zag(int i){     int t=tree[i].rc;     tree[i].rc=tree[t].lc;     tree[t].lc=i;     tree[i].h=max(tree[tree[i].lc].h,tree[tree[i].rc].h)+1;     tree[t].h=max(tree[tree[t].lc].h,tree[tree[t].rc].h)+1;     return t; } inline int zagzig(int i){     tree[i].lc=zag(tree[i].lc);     return zig(i); } inline int zigzag(int i){     tree[i].rc=zig(tree[i].rc);     return zag(i); }    void Insert(int &tmp,int x){     if(!tmp)     {         tree[++cnt].data=x;         tree[cnt].h=1;         tmp=cnt;         return;     }     M=min(abs(tree[tmp].data-x),M);     if(x<tree[tmp].data)     {         Insert(tree[tmp].lc,x);         if(tree[tree[tmp].lc].h==tree[tree[tmp].rc].h+2)         {             if(x<tree[tree[tmp].lc].data) tmp=zig(tmp);             else if(x>tree[tree[tmp].lc].data) tmp=zagzig(tmp);         }     }     else if(x>tree[tmp].data)     {         Insert(tree[tmp].rc,x);         if(tree[tree[tmp].rc].h==tree[tree[tmp].lc].h+2)         {             if(x>tree[tree[tmp].rc].data) tmp=zag(tmp);             else if(x<tree[tree[tmp].rc].data) tmp=zigzag(tmp);         }     }     tree[tmp].h=max(tree[tree[tmp].lc].h,tree[tree[tmp].rc].h)+1; } int main(){     Get_int(n); Get_int(t1);     Insert(root,t1);     ans=t1;     for(int i=1;i<n;i++)     {         M=INT_MAX;         Get_int(t1);         Insert(root,t1);         ans+=M;     }     printf("%d",ans); } 


现在解释下为什么M=min(abs(tree[tmp].data-x),M);这条语句可以处理出该天的最小波动值
首先是这条语句的含义:
它实际上是指在Insert操作寻找的路径上找到最小波动值
但有一个疑点就是:为什么该天的最小波动值一定在Insert所寻找的路径上,而不是在其他的点上

运用假设法来证明:
如果存在一个点具有一个比当前最小波动值更小的值,
那么这个点只可能存在于Insert所寻找路径的旁边(即这一条路径上向左或向右延伸出去的某个点)
所以,假设该天的营业额为x,它在它某个祖先i的左子树上,该祖先与x具有一个在Insert路径上的最小波动值
那么可能具有更小波动值的节点只可能是i的右节点,记作rson(i)
根据二叉查找树的性质,有x<i.data<rson(i).data
显然,i的最小波动值比rson(i) 更小

其他节点与x在i的右子树上的证法可以以此类推


好了,第1篇博客搞定,写得差别怪我

0 0
原创粉丝点击