HNOI 2002 营业额统计 Splay Tree

1588: [HNOI2002]营业额统计

Time Limit: 5 Sec   Memory Limit: 162 MB
Submit: 3822   Solved: 1184
[ Submit][ Status][ Discuss]

Description

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

Input

第一行为正整数 ,表示该公司从成立一直到现在的天数,接下来的n行每行有一个正整数 ,表示第i天公司的营业额。

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

Source

#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
int N, M, rt, cnt;
const int MN = 1100010;
int ch[MN][2], pre[MN], val[MN];
int newnode ( int x, int p, int v ) {///创建新节点
	ch[x][0] = ch[x][1] = 0, pre[x] = p;
	val[x] = v;///节点上的数值
	return x;
}
void rotate ( int x, int f ) {///把第k位的数转到f下边
    ///类似SBT,要把其中一个分支先给父节点
	int y = pre[x], z = pre[y];
	ch[y][!f] = ch[x][f], pre[ ch[x][f] ] = y;
	ch[x][f] = y, pre[ y ] = x;
	pre[x] = z;
	if ( z ) ch[z][ ch[z][1] == y ] = x;	///如果父节点不是根结点,则要和父节点的父节点连接起来
}
int insert ( int &x, int p, int v ) {///插入
	if ( x == 0 ) {
		return newnode ( x = cnt++, p, v );
	} else {
		return insert ( ch[x][ val[x] < v ], x, v );
	}
}
int splay ( int x, int f ) {///Splay调整,将根为r的子树调整为f
	while ( pre[x] != f ) {
		int y = pre[x], z = pre[y];
		if ( z == f ) rotate ( x, ch[y][0] == x );
		else {
			int f = ( ch[z][1] == y );
			if ( ch[y][!f] == x ) {			///两个方向不同,则先左旋再右旋
				rotate ( x, f ), rotate ( x, !f );
			} else {			///两个方向相同,相同方向连续两次
				rotate ( y, !f ), rotate ( x, !f );
			}
		}
	}
	if ( f == 0 ) rt = x;	///更新根结点
}
int findMax ( int rt ) {
	return ch[rt][1] == 0 ? rt : findMax ( ch[rt][1] );
}
int findMin ( int rt ) {
	return ch[rt][0] == 0 ? rt : findMin ( ch[rt][0] );
}
void print ( int rt ) {
	if ( rt == 0 ) return;
	print ( ch[rt][0] );
	printf ( "%4d", val[rt] );
	print ( ch[rt][1] );
}
int main ()
{
   // freopen("//media/学习/ACM/input.txt","r",stdin);
	while ( scanf ( "%d", &N ) == 1 ) {
		ch[0][1] = ch[0][0] = val[0] = pre[0] = 0;///
		cnt = 1, rt = 0;
		int sum = 0;
		int mi, ma;
		for ( int i = 1; i <= N; ++ i ) {
           if(scanf("%d",&M)==EOF) M=0;
			int pos = insert ( rt, 0, M );
			splay ( pos, 0 );
			if ( i>1 && ch[rt][1] == 0 ) mi = -0x5ffffff;
			else mi = val[ findMin ( ch[rt][1] ) ];
			if ( i>1 && ch[rt][0] == 0 ) ma = -0x5ffffff;
			else ma = val[ findMax ( ch[rt][0] ) ];
			if(i==1)sum=abs(M);
			else sum += min ( abs( M-mi ), abs( M-ma ) );
			//cout<<"step "<<i<<" "<<sum<<endl;
		}
		//cout<<"result : ";
		printf ( "%d\n", sum);
	}
	return 0;
}




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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值