「HNOI2002」 营业额统计 - 平衡树/STL set

题目描述

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;
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值