[luogu P2234] [HNOI2002]营业额统计

本文介绍了一道经典算法题“营业额统计”,使用Treap数据结构解决最小波动值的计算问题,通过查找前驱和后继节点实现高效更新。

[luogu P2234] [HNOI2002]营业额统计

题目描述

Tiger最近被公司升任为营业部经理,他上任后接受公司交给的第一项任务便是统计并分析公司成立以来的营业情况。

Tiger拿出了公司的账本,账本上记录了公司成立以来每天的营业额。分析营业情况是一项相当复杂的工作。由于节假日,大减价或者是其他情况的时候,营业额会出现一定的波动,当然一定的波动是能够接受的,但是在某些时候营业额突变得很高或是很低,这就证明公司此时的经营状况出现了问题。经济管理学上定义了一种最小波动值来衡量这种情况:

当最小波动值越大时,就说明营业情况越不稳定。

而分析整个公司的从成立到现在营业情况是否稳定,只需要把每一天的最小波动值加起来就可以了。你的任务就是编写一个程序帮助Tiger来计算这一个值。

第一天的最小波动值为第一天的营业额。

该天的最小波动值=min{|该天以前某一天的营业额-该天营业额|}。

输入输出格式

输入格式:

 

输入由文件’turnover.in’读入。

第一行为正整数n(n<=32767) ,表示该公司从成立一直到现在的天数,接下来的n行每行有一个整数ai(|ai|<=1000000) ,表示第i天公司的营业额,可能存在负数。

 

输出格式:

 

 

输入输出样例

输入样例#1: 复制
6
5
1
2
5
4
6
输出样例#1: 复制
12

说明

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

 

一起用splay做这道题,现在再用treap写,感觉完全不一样。。。

treap真是个好东西。。。(但splay当然也有其优点)

这道题就是找一下前驱后继罢了。

code:

 1 %:pragma GCC optimize(2)
 2 #include<bits/stdc++.h>
 3 #define Ms(a,x) memset(a,x,sizeof a)
 4 using namespace std;
 5 const int N=32768;
 6 int n,m,root,ans,final;
 7 class treap{
 8     private:
 9         int ch[N][2],v[N],k[N],s[N];
10     public:
11         treap() {Ms(ch,0);}
12         inline void newnode(int &cur,int x) {
13             cur=++n,v[cur]=x,s[cur]=1,k[cur]=rand();
14         }
15         inline void update(int cur) {
16             s[cur]=s[ch[cur][0]]+s[ch[cur][1]]+1;
17         }
18         inline void rotate(int &cur,int dir) {
19             int tmp=ch[ch[cur][dir^1]][dir];
20             ch[ch[cur][dir^1]][dir]=cur;
21             cur=ch[cur][dir^1];
22             ch[ch[cur][dir]][dir^1]=tmp;
23             update(ch[cur][dir]),update(cur);
24         }
25         inline void insert(int &cur,int x) {
26             if (!cur) {newnode(cur,x); return;}
27             if (v[cur]==x) {s[cur]++; return;}
28             bool q=v[cur]<x;
29             insert(ch[cur][q],x);
30             if (k[cur]>k[ch[cur][q]]) rotate(cur,q^1); else update(cur);
31         }
32         inline void x_pre(int cur,int x) {
33             if (!cur) return;
34             if (v[cur]>x) x_pre(ch[cur][0],x);
35             else ans=v[cur],x_pre(ch[cur][1],x);
36         }
37         inline void x_suc(int cur,int x) {
38             if (!cur) return;
39             if (v[cur]<x) x_suc(ch[cur][1],x);
40             else ans=v[cur],x_suc(ch[cur][0],x);
41         }
42 }t;
43 inline int read() {
44     int x=0,f=1; char ch=getchar();
45     while (ch<'0'||ch>'9') f=(ch=='-')?-1:1,ch=getchar();
46     while (ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar();
47     return x*f;
48 }
49 int main() {
50     srand(520),root=final=n=0,m=read();
51     for (int i=1,x,u,v,get; i<=m; i++) {
52         x=read();
53         if (i==1) get=x; else  {
54             ans=-1e9,t.x_pre(root,x),get=x-ans;
55             ans=1e9,t.x_suc(root,x),get=min(get,ans-x);
56         }
57         final+=get,t.insert(root,x);
58     }
59     return cout<<final<<endl,0;
60 }
View Code

 

转载于:https://www.cnblogs.com/whc200305/p/7744990.html

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符  | 博主筛选后可见
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值