题目描述
Tiger最近被公司升任为营业部经理,他上任后接受公司交给的第一项任务便是统计并分析公司成立以来的营业情况。
Tiger拿出了公司的账本,账本上记录了公司成立以来每天的营业额。分析营业情况是一项相当复杂的工作。由于节假日,大减价或者是其他情况的时候,营业额会出现一定的波动,当然一定的波动是能够接受的,但是在某些时候营业额突变得很高或是很低,这就证明公司此时的经营状况出现了问题。经济管理学上定义了一种最小波动值来衡量这种情况:
该天的最小波动值=min { | 该天以前的某天的营业额-该天的营业额 | }
当最小波动值越大时,就说明营业情况越不稳定。
而分析整个公司的从成立到现在营业情况是否稳定,只需要把每一天的最小波动值加起来就可以了。你的任务就是编写一个程序帮助Tiger来计算这一个值。
第一天的最小波动值为第一天的营业额。
输入格式
第一行为正整数n(n<=32767) ,表示该公司从成立一直到现在的天数
接下来的n行每行有一个整数a(绝对值小于等于1000000) ,表示第i天公司的营业额。
输出格式
输出仅有一个正整数,即每一天的最小波动值的总和。结果小于2^31 。
分析
平衡树求前驱与后继,也可以用STL set。说明以下STL set中lower_bound(x),是查找set中大于等于x的元素中最小的一个,若没有则返回end(),否则返回该元素的迭代器。没有用multiset的原因是set中对于重复元素直接忽略不计,又不需要用到重复的元素,所以用set就本题来讲没有影响。
代码
Treap版本。
#include <iostream>
#include <cstdlib>
#include <cstdio>
#define abs(a) ((a)<0?-(a):a)
using namespace std;
const int N=100005;
const int INF=0x7fffffff;
struct Node {
int l,r;
int val,dat;
int cnt,size;
} a[N];
int tot,root;
int New(int val) {
a[++tot].val=val;
a[tot].dat=rand();
a[tot].size=a[tot].cnt=1;
return tot;
}
void Update(int p) {
a[p].size=a[a[p].l].size+a[a[p].r].size+a[p].cnt;
}
void Build() {
New(-INF);
New(INF);
root=1;
a[1].r=2;
Update(root);
}
void zig(int &p) {
int q=a[p].l;
a[p].l=a[q].r;
a[q].r=p;
p=q;
Update(a[p].r);
Update(p);
}
void zag(int &p) {
int q=a[p].r;
a[p].r=a[q].l;
a[q].l=p;
p=q;
Update(a[p].l);
Update(p);
}
void Insert(int &p,int val) {
if (p==0) {
p=New(val);
return;
}
if (a[p].val==val) {
a[p].cnt++;
Update(p);
return;
}
if (a[p].val>val) {
Insert(a[p].l,val);
if (a[p].dat<a[a[p].l].dat) zig(p);
} else {
Insert(a[p].r,val);
if (a[p].dat<a[a[p].r].dat) zag(p);
}
Update(p);
}
int GetPre(int val) {
int ans=1;
int p=root;
while (p) {
if (val==a[p].val) {
ans=p;
break;
if (a[p].l>0) {
p=a[p].l;
while (a[p].r>0) p=a[p].r;
ans=p;
}
break;
}
if (a[p].val<val&&a[p].val>a[ans].val) ans=p;
p=val<a[p].val?a[p].l:a[p].r;
}
return a[ans].val;
}
int GetNext(int val) {
int ans=2;
int p=root;
while (p) {
if (val==a[p].val) {
ans=p;
break;
if (a[p].r>0) {
p=a[p].r;
while (a[p].l>0) p=a[p].l;
ans=p;
}
break;
}
if (a[p].val>val&&a[p].val<a[ans].val) ans=p;
p=val<a[p].val?a[p].l:a[p].r;
}
return a[ans].val;
}
int main() {
Build();
int n,ans=0;
scanf("%d",&n);
for (int i=1;i<=n;i++) {
int x;
scanf("%d",&x);
if (i==1) ans+=x;
else {
int t=GetPre(x),p=GetNext(x);
if (p==INF||p==-INF) ans+=abs(t-x);
else if (t==INF||t==-INF) ans+=abs(p-x);
else ans+=min(abs(t-x),abs(p-x));
}
Insert(root,x);
}
printf("%d",ans);
return 0;
}
STL set版本。
#include <algorithm>
#include <iostream>
#include <iomanip>
#include <cstring>
#include <cstdio>
#include <queue>
#include <set>
using namespace std;
typedef long long LL;
int n,ans;
set<int> s;
set<int>::iterator it;
int main() {
scanf("%d",&n);
for (int i=1;i<=n;i++) {
int a,dt=0x7fffffff/2;
scanf("%d",&a);
if (s.empty()) {
ans+=a;
s.insert(a);
continue;
}
it=s.lower_bound(a);
if (it!=s.end()) {
dt=min(dt,abs(*it-a));
}
if (it!=s.begin()) {
it--;
dt=min(dt,abs(*it-a));
}
ans+=dt;
s.insert(a);
}
printf("%d",ans);
return 0;
}