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

[HNOI2002]营业额统计

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

 [HNOI2002]营业额统计

Time Limit: 5 Sec   Memory Limit: 162 MB
Submit: 4128   Solved: 1305
[ 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

 
 

题意就是每读入一个数,在前面输入的数中找到一个与该数相差最小的一个。把所有的差值加起来。

三个操作:插入、求前驱、求后继。

 

简单的Splay tree入门题。照着别人代码写的。

 

#include <stdio.h>

#include <string.h>

#include <iostream>

#include <algorithm>

using namespace std;

const int N=100005;

const int INF=0x3f3f3f3f;

int pre[N],key[N],ch[N][2],root,tot1;

//分别表示父结点,键值,左右孩子(0左1右),根结点,结点数量

int n;

//新建一个结点

void NewNode(int &r,int father,int k)

{

    r=++tot1;

    pre[r]=father;

    key[r]=k;

    ch[r][0]=ch[r][1]=0;//左右孩子为空

}

//旋转,kind为1是右旋,为0是左旋

void Rotate(int x,int kind)

{

    int y=pre[x];

    ch[y][!kind]=ch[x][kind];

    pre[ch[x][kind]]=y;

    if(pre[y])

      ch[pre[y]][ch[pre[y]][1]==y]=x;

    pre[x]=pre[y];

    ch[x][kind]=y;

    pre[y]=x;

}

//Splay调整,将结点r调整到goal下面

void Splay(int r,int goal)

{

    while(pre[r]!=goal)

    {

        if(pre[pre[r]]==goal)Rotate(r,ch[pre[r]][0]==r);

        else

        {

            int y=pre[r];

            int kind=ch[pre[y]][0]==y;

            if(ch[y][kind]==r)

            {

                Rotate(r,!kind);

                Rotate(r,kind);

            }

            else

            {

                Rotate(y,kind);

                Rotate(r,kind);

            }

        }

    }

    //更新根结点

    if(goal==0)root=r;

}

int Insert(int k)

{

    int r=root;

    while(ch[r][key[r]<k])

    {

        //不重复插入

        if(key[r]==k)

        {

            Splay(r,0);

            return 0;

        }

        r=ch[r][key[r]<k];

    }

    NewNode(ch[r][key[r]<k],r,k);

    Splay(ch[r][key[r]<k],0);

    return 1;

}

//找前驱

int get_pre(int x)

{

    int tmp=ch[x][0];

    if(tmp==0)return INF;

    while(ch[tmp][1])

      tmp=ch[tmp][1];

    return key[x]-key[tmp];

}

//找后继

int get_next(int x)

{

    int tmp=ch[x][1];

    if(0==tmp) return INF;

    while(ch[tmp][0])

      tmp=ch[tmp][0];

    return key[tmp]-key[x];

}

int main()

{

    while(scanf("%d",&n)==1)

    {

        root=tot1=0;

        int ans=0;

        for(int i=1;i<=n;i++)

        {

            int num;

            if(scanf("%d",&num)==EOF)num=0;//这是变态之处==

            if(i==1)

            {

                ans+=num;

                NewNode(root,0,num);

                continue;

            }

            if(Insert(num)==0)continue;

            int a=get_pre(root);

            int b=get_next(root);

            ans+=min(a,b);

        }

        printf("%d\n",ans);

    }

    return 0;

}

 

你可能感兴趣的:(tree)