现在的位置: 首页 > 综合 > 正文

[HNOI2002]营业额统计 Splay tree入门题

2018年12月26日 ⁄ 综合 ⁄ 共 2198字 ⁄ 字号 评论关闭

题目连接:http://www.lydsy.com/JudgeOnline/problem.php?id=1588

1588: [HNOI2002]营业额统计

Time Limit: 5 Sec  Memory Limit: 162 MB
Submit: 6068  Solved: 1981
[Submit][Status]

Description

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

Input

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

Output

输出文件仅有一个正整数,即Sigma(每天最小的波动值) 。结果小于2^31 。

Sample Input

6

5

1

2

5

4

6

Sample Output

12




#include<stdio.h>
#include<string.h>
const int N=100100;
const int inf=0x3fffffff;
#define min(a,b) (a>b?b:a)
int root,tot;
struct Tree
{
	int key,son[2],father;
}T[N];//son[0]左儿子,son[1]右儿子
void newnode(int &r,int w,int fa)//建新节点
{
	r=++tot;
	T[r].key=w;T[r].father=fa;
	T[r].son[0]=T[r].son[1]=0;
}
void Rotate(int r,int kind)//旋转,kind为1是右旋,为0是左旋
{
	int y=T[r].father;
	T[y].son[!kind]=T[r].son[kind];
	T[T[r].son[kind]].father=y;
	if(T[y].father)
        T[T[y].father].son[T[T[y].father].son[1]==y]=r;
	T[r].father=T[y].father;
	T[r].son[kind]=y;
	T[y].father=r;
}
//Splay调整,将结点r调整到goal下面(以r为根节点)
void Splay(int r,int goal)
{
	int y;
	while(T[r].father!=goal)
	{
		y=T[r].father;
		if(T[y].father==goal)
			Rotate(r,T[y].son[0]==r);
		else
		{			
			int kind=T[T[y].father].son[0]==y;
			if(T[y].son[kind]==r)
			{
				Rotate(r,!kind);
				Rotate(r,kind);
			}
			else
			{
				Rotate(y,kind);
				Rotate(r,kind);
			}
		}
	}
	if(goal==0)root=r;//更新根节点
}
bool insert(int w)
{
	int r=root;
	while(T[r].son[w>T[r].key])
	{
		if(T[r].key==w)//如果w已经在树中
		{
			Splay(r,0);
			return false;
		}
		r=T[r].son[w>T[r].key];
	}
	newnode(T[r].son[w>T[r].key],w,r);
	Splay(T[r].son[w>T[r].key],0);
	return true;
}
int get_pre(int r)//在左子树中找到最大的值(找前驱)
{
	int temp=T[r].son[0];
	if(temp==0)return inf;
	while(T[temp].son[1])
		temp=T[temp].son[1];
	return T[r].key-T[temp].key;
}
int get_next(int r)//在右子树中找到最小的值(找后继)
{
	int temp=T[r].son[1];
	if(temp==0)return inf;
	while(T[temp].son[0])
		temp=T[temp].son[0];
	return T[temp].key-T[r].key;
}
int main()
{
	int n,w,sum,j;
	while(scanf("%d",&n)!=-1)
	{
		sum=0;root=tot=0;		
		if(scanf("%d",&w)==EOF)w=0;			
		sum+=w;
		newnode(root,w,0);
		for(j=1;j<n;j++)
		{
			if(scanf("%d",&w)==EOF)w=0;			
			if(!insert(w))continue;
			sum+=min(get_pre(root),get_next(root));
		}
		printf("%d\n",sum);
	}
	return 0;
}

【上篇】
【下篇】

抱歉!评论已关闭.