BZOJ1588 [HNOI2002]营业额统计——Treap的应用

Description

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

Input

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


对于每一天的营业额,找出前几天和它差值最小的营业额,再累加这个差值,就是题目所需的答案。我们只要求出前几天与这天最相近的营业额即可。

那么我们怎么找出这营业额呢?这里非常容易想到用二叉搜索树,因为二叉搜索树满足对于值的有序的性质,我们运用Treap,找出每天营业额的前驱和后继,将前驱和后继和其做差,取min即可。

怎么求前驱和后继?链接点击这里

CODE:

#include
#define lc f[k].l
#define rc f[k].r
#define INF 20000000
using namespace std;

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

struct node{
    int l,r,ct,val,siz,ran;
}f[40000];

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

int num,ans,root,n,i;

void up(int k){f[k].siz=f[lc].siz+f[rc].siz+f[k].ct;}

void lturn(int &k){
    int x=f[k].r;f[k].r=f[x].l;f[x].l=k;
    f[x].siz=f[k].siz;up(k);k=x;
}

void rturn(int &k){
    int x=f[k].l;f[k].l=f[x].r;f[x].r=k;
    f[x].siz=f[k].siz;up(k);k=x;
}

void ins(int &k,int x){
    if(k==0){
        k=++num;
        f[k].ct=f[k].siz=1;f[k].ran=rand();f[k].val=x;
        return;
    }
    f[k].siz++;
    if(f[k].val==x) f[k].ct++;
    else if(f[k].val<x){
        ins(rc,x);
        if(f[k].ran>f[rc].ran) lturn(k);
    }else{
        ins(lc,x);
        if(f[k].ran>f[rc].ran) rturn(k);
    }
}

int findbf(int k,int x){
    if(k==0) return -INF;
    if(x>f[k].val) return max(f[k].val,findbf(rc,x));
    else if(x<=f[k].val) return findbf(lc,x);
}

int findaf(int k,int x){
    if(k==0) return INF;
    if(x>=f[k].val) return findaf(rc,x);
    else return min(f[k].val,findaf(lc,x));
}

int find(int k,int x){
    if(f[k].val==x){
        if(f[k].ct>1) return 0;
        return min(abs(findaf(root,x)-x),abs(findbf(root,x)-x));
    }
    else if(f[k].val>x) return find(lc,x);
    else return find(rc,x);
}

int main()
{
    n=read();
    for(int i=1;i<=n;i++){
        int x=read();
        ins(root,x);
        if(i==1) ans+=x;
        else ans+=find(root,x);
    }
    printf("%d",ans);
    return 0;
}

你可能感兴趣的:(BZOJ)