BZOJ 1588 HNOI2002 营业额统计

1588: [HNOI2002]营业额统计

Time Limit: 5 Sec  Memory Limit: 162 MB
Submit: 17427  Solved: 7104
[Submit][Status][Discuss]
Description

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

Input

第一行为正整数 ,表示该公司从成立一直到现在的天数,接下来的n行每行有一个整数(有可能有负数) ,表示第i
天公司的营业额。
天数n<=32767,
每天的营业额ai <= 1,000,000。
最后结果T<=2^31
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


该题数据bug已修复.----2016.5.15
题目

刚开始看道题的时候看不懂

这道题目的大意就是对于每一个i找到i之前离a[i]最接近的数,他们俩的差值作为波动,最后累加

维护区间查询离某个值最近当然Treep更好用一些,getprev和getnext函数查询大和小最近的

一比较即可

代码如下:

 1 #include <bits/stdc++.h>
 2 #define ll long long 
 3 using namespace std;
 4 inline int read(){
 5     int x=0;int f=1;char ch=getchar();
 6     while(!isdigit(ch)) {if(ch=='-') f=-1;ch=getchar();}
 7     while(isdigit(ch)) {x=x*10+ch-'0';ch=getchar();}
 8     return x*f;
 9 }
10 const int MAXN=1e6+10;
11 namespace zhangenming{
12     int n,a[MAXN],root=0,cnt=0;
13     struct tree{
14         int leftt,rightt,v,fix;
15     }T[MAXN<<1];
16     inline void left_rota(int &root){
17         int k=T[root].rightt;
18         T[root].rightt=T[k].leftt;
19         T[k].leftt=root;
20         root=k;
21     }
22     inline void right_rota(int &root){
23         int k=T[root].leftt;
24         T[root].leftt=T[k].rightt;
25         T[k].rightt=root;
26         root=k;
27     }
28     inline void myinsert(int &root,int x){
29         //cout<<root<<' '<<x<<endl; 
30         if(root==0){
31             root=++cnt;
32             T[root].v=x;
33             T[root].fix=rand()&1007;
34             return;
35         }
36         if(x==T[root].v){
37             return;
38         }
39         else{
40             if(x>T[root].v){
41                 myinsert(T[root].rightt,x);
42                 if(T[T[root].rightt].fix>T[root].fix) left_rota(root); 
43             }
44             else{
45                 myinsert(T[root].leftt,x);
46                 if(T[T[root].leftt].fix>T[root].fix) right_rota(root);
47             }
48         }
49     }
50     inline int getnext(int root,int x){
51         if(root==0) return 100000000;
52         if(T[root].v<x) return getnext(T[root].rightt,x);
53         else {
54             return min(T[root].v,getnext(T[root].leftt,x));
55         }
56     }
57     inline int getprev(int root,int x){
58         if(root==0) return -1000000;
59         if(T[root].v>x){
60             return getprev(T[root].leftt,x);
61         }
62         else return max(T[root].v,getprev(T[root].rightt,x));
63     }
64     void init(){
65         n=read();
66         for(int i=1;i<=n;i++){
67             a[i]=read();
68         }
69     }
70     void solve(){
71         ll sum=a[1];
72         memset(T,0,sizeof(T));
73         myinsert(root,a[1]);
74         for(int i=2;i<=n;i++){
75             int k=getprev(root,a[i]);
76             //cout<<k<<' ';
77             int l=getnext(root,a[i]);
78             //cout<<l<<endl;
79             sum+=min(abs(k-a[i]),abs(l-a[i]));
80             //cout<<sum<<endl;
81             myinsert(root,a[i]);
82         }
83         
84         cout<<sum<<endl;
85     }
86 }
87 int main(){
88     //freopen("All.in","r",stdin);
89     //freopen("a.out","w",stdout);
90     srand(int(time(NULL)));
91     using namespace zhangenming;
92     init();
93     solve();
94     return 0;
95 }
View Code

码了半个小时QAQ

posted @ 2017-11-15 17:16  zhangenming  阅读(133)  评论(0编辑  收藏  举报