bzoj1588: [HNOI2002]营业额统计

bzoj1588

Description

Tiger最近被公司升任为营业部经理,他上任后接受公司交给的第一项任务便是统计并分析公司成立以来的营业情况。
Tiger拿出了公司的账本,账本上记录了公司成立以来每天的营业额。分析营业情况是一项相当复杂的工作。由于节假日,大减价或者是其他情况的时候,营业额会出现一定的波动,当然一定的波动是能够接受的,但是在某些时候营业额突变得很高或是很低,这就证明公司此时的经营状况出现了问题。经济管理学上定义了一种最小波动值来衡量这种情况:
=min{||}

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中查找前驱和后继即可。

#include<cmath>
#include<cstdio>
#include<iostream>
#include<algorithm>
using namespace std;

const int N = 33000, inf = 1 << 30;
struct Splay{
    int a;
    Splay *c[2], *f;

    int d(){return f->c[1] == this;}
    void sc(Splay* x, int d){(c[d] = x)->f = this;}
};

Splay *null = new Splay();
Splay *root = new Splay();

void rotate(Splay *x){
    int d = x->d();
    Splay* p = x->f;
    p->sc(x->c[!d], d);
    if(p == root) x->f = null, root = x;
    else p->f->sc(x, p->d());
    x->sc(p, !d);
}

void splay(Splay *x){
    for(Splay* y; x != root; ){
        y = x->f;
        if(y != root) (x->d() ^ y->d()) ? rotate(x): rotate(y);
        rotate(x);
    }
}

void insert(Splay *q){
    Splay *p = root;
    for(;;){
        int d = q->a > p->a;
        if(p->c[d] != null) p = p->c[d];
        else {p->sc(q, d), splay(q); break;}
    }
}

int n, ans;

void init(){
    scanf("%d", &n);
}
void work(){
    int x; Splay *q, *tmp;
    null->a = inf;

    scanf("%d", &x);
    q = new Splay();
    q->a = x; q->c[0] = q->c[1] = q->f = null;
    root = q;
    ans += x;

    for(int i = 1; i < n; i++){
        scanf("%d", &x);
        q = new Splay();
        q->a = x; q->c[0] = q->c[1] = q->f = null;
        insert(q);
        int t1 = inf, t2 = inf;
        if(q->c[0] != null){
            tmp = q->c[0];
            while(null != tmp->c[1]) tmp = tmp->c[1];
            t1 = tmp->a;
        }
        if(q->c[1] != null){
            tmp = q->c[1];
            while(null != tmp->c[0]) tmp = tmp->c[0];
            t2 = tmp->a;
        }
        ans += min(abs(x - t1), abs(t2 - x));
    }
    printf("%d\n", ans);
}
int main(){
    freopen("turnover.in", "r", stdin);
    freopen("turnover.out", "w", stdout);
    init();
    work();
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值