bzoj1588: [HNOI2002]营业额统计(平衡树)

原题链接

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

输入格式:第一行为正整数 ,表示该公司从成立一直到现在的天数,接下来的n行每行有一个整数(有可能有负数) ,表示第i
天公司的营业额。天数n<=32767,每天的营业额ai <= 1,000,000。最后结果T<=2^31。

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

输入样例
6
5
1
2
5
4
6

输出样例
12

解析:平衡树的模板题。
   每次求一次前驱和后继求一个最小值相加即可。

代码如下:

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

const int maxn = 40005;
int n, root, ans;
int a[maxn], size[maxn], c[maxn], pri[maxn], cnt, lson[maxn], rson[maxn];

int read(void) {
    char c; while (c = getchar(), (c < '0' || c > '9') && c != '-'); int x = 0, y = 1;
    if (c == '-') y = -1; else x = c - '0';
    while (c = getchar(), c >= '0' && c <= '9') x = x * 10 + c - '0'; return x * y; 
}

int rand(){
    static int seed = 2333;
    return seed = (int)((((seed ^ 998244353) + 19260817ll) * 19890604ll) % 1000000007);
}

void up(int k) {
    size[k] = size[lson[k]] + size[rson[k]] + c[k];
}

void zig(int &k) {
    int v = rson[k]; rson[k] = lson[v]; lson[v] = k;
    size[v] = size[k]; up(k); k = v;
}

void zag(int &k) {
    int v = lson[k]; lson[k] = rson[v]; rson[v] = k;
    size[v] = size[k]; up(k); k = v;
}

void insert(int &k, int x) {
    if (k == 0) {
      k = ++ cnt;
      a[k] = x; size[k] = c[k] = 1; pri[k] = rand();
      return;
    }
    size[k] ++;
    if (a[k] == x) c[k] ++;
    else if (x > a[k]) {
      insert(rson[k], x);
      if (pri[rson[k]] < pri[k]) zig(k);
    }
    else {
      insert(lson[k], x);
      if (pri[lson[k]] < pri[k]) zag(k);
    }
}

int query_pre(int &k, int x) { //求前驱 
    if (k == 0) return -2e9;
    if (x >= a[k]) return max(a[k], query_pre(rson[k], x));
    else return query_pre(lson[k], x);
}

int query_next(int &k, int x) { //求后继 
    if (k == 0) return 2e9;
    if (x <= a[k]) return min(a[k], query_next(lson[k], x));
    else return query_next(rson[k], x);
}

int main() {
    n = read();
      for (int i = 1; i <= n; ++ i) {
        int x = read();
        int tmpx = query_pre(root, x), tmpy = query_next(root, x);
        if (tmpx == -2e9 && tmpy == 2e9) ans += x;
        else if (tmpx == -2e9) ans += abs(x - tmpy);
        else if (tmpy == 2e9) ans += abs(x - tmpx);
        else ans += min(abs(x - tmpx), abs(x - tmpy));
        insert(root, x);
      }
    printf("%d", ans);
    return 0; 
}

猜你喜欢

转载自www.cnblogs.com/Gaxc/p/10125167.html