【HYSBZ1588: [HNOI2002]】营业额统计——伸展树

Time Limit: 5 Sec Memory Limit: 162 MB

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

该题数据bug已修复.—-2016.5.15

伸展树初步,在看完网上对伸展树的基本操作后,试着敲了敲,发现了自己的Zig和Zag敲错了,好惨。用链表的,感觉写的很挫,慢慢的变得精炼的。
思路:每一次将插入的数提到根节点,那么对于一二叉查找树来说,根节点的前驱就是左子树的最右边的节点,后继就是右子树最左边的节点。那么就可以得到最小的波动值。

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cmath>
#include <cstring>
#include <string>
#include <queue>
#include <stack>
#include <set>
#include <map>
#include <vector>
#include <algorithm>
using namespace std;
typedef long long LL;
const int INF = 0x3f3f3f3f;
typedef struct node{

    int data;

    node *Lch,*Rch,*fa;
}Tree;

Tree * Creat(int data){
    Tree *p ;

    p = new node;

    p->data = data;

    p->Lch = p->Rch = p->fa = NULL;

    return p;
}

Tree * Insert(int data,Tree * u){//插入节点
    if(u->data == data)
        return NULL;

    if(u->data>data){
        if(u->Lch == NULL){
            u->Lch = Creat(data);

            u->Lch ->fa = u;

            return u->Lch;
        }
        else
            return Insert(data,u->Lch);
    }
    else{
        if(u->Rch == NULL){
            u->Rch = Creat(data);

            u->Rch->fa = u;

            return u->Rch;
        }
        else
            return Insert(data,u->Rch);
    }
    return NULL;
}

void Zig(Tree *u){//右旋
    Tree *fa,*p,*Gfa;

    bool flag = false;

    fa = u->fa;

    Gfa = fa->fa;

    if(Gfa&&Gfa->Rch == fa)
        flag = true;

    p = u->Rch;

    u->fa = Gfa;

    u->Rch = fa;

    fa->fa = u;

    fa->Lch = p;

    if(p)
        p->fa = fa;

    if(Gfa){
        if(flag)
            Gfa->Rch = u;
        else Gfa->Lch = u;
    }
}
void Zag(Tree * u){//左旋
    Tree *fa ,*p,*Gfa;

    bool flag = false;

    fa = u->fa ;

    Gfa= fa->fa;

    if(Gfa&&Gfa->Rch == fa)
        flag = true;

    p = u->Lch;

    u->fa = fa->fa;

    u->Lch = fa;

    fa->fa = u;

    fa->Rch = p;

    if(p)
        p->fa = fa;

    if(Gfa){
        if(flag)
            Gfa->Rch = u;
        else Gfa->Lch = u;
    }
}
Tree * Rotate(Tree *u){//将节点提到根处。
    Tree *fa , *Gfa;

    while(u->fa != NULL){
        fa = u->fa;

        Gfa = fa->fa;

        if(Gfa == NULL){
            if(fa->Lch == u)
                Zig(u);
            else
                Zag(u);
        }
        else{
            if(Gfa->Lch == fa){
                if(fa->Lch == u)
                    Zig(u);
                else
                    Zag(u);

                Zig(u);
            }
            else{
                if(fa->Lch == u)
                    Zig(u);
                else
                    Zag(u);

                Zag(u);
            }
        }
    }
    return u;
}
int Find_Pre(Tree *u,int data){//找节点的前驱
    if(u == NULL) return INF;

    if(u->Rch == NULL) return data-u->data;

    else return Find_Pre(u->Rch,data);
}
int Find_Next(Tree *u,int data){//找节点的后继
    if(u == NULL) return INF;

    if(u->Lch == NULL) return u->data-data;

    else return Find_Next(u->Lch,data);
}
int main(){
    int n;
    while(~scanf("%d",&n)){
        Tree *root,*p;

        int ans = 0,data;

        for(int i = 0;i < n; i++){

            scanf("%d",&data);

            if(!i){
                ans += abs(data);

                root = Creat(data);
            }
            else{
                 p = Insert(data,root);

                 if(p == NULL) continue;

                 root = Rotate(p);

                 int a = Find_Pre(root->Lch,data);

                 int b = Find_Next(root->Rch,data);

                 ans+=min(a,b);
            }
        }

        printf("%d\n",ans);
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值