bzoj1588: [HNOI2002]营业额统计(权值线段树)

1588: [HNOI2002]营业额统计

Time Limit: 5 Sec  Memory Limit: 162 MB
Submit: 16863  Solved: 6789
[Submit][Status][Discuss]

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


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

/*
离散化
权值线段树查询前驱后继 
*/
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>

#define inf 0x3f3f3f3f
#define N 40000

using namespace std;
struct tree
{
    int l,r,mx,mn,sum;
}tr[N<<2];
int n,m,ans,tot,cnt;
int a[N],b[N],val[N],num[N];

inline void pushup(int k)
{
    tr[k].sum=tr[k<<1].sum+tr[k<<1|1].sum;
    if(tr[k].sum)
    {
      tr[k].mn=min(tr[k<<1].mn,tr[k<<1|1].mn);
      tr[k].mx=max(tr[k<<1].mx,tr[k<<1|1].mx);
    } 
}

void build(int k,int l,int r)
{
    tr[k].l=l;tr[k].r=r;tr[k].mn=inf;tr[k].mx=0;
    if(l==r)
    {
        tr[k].sum=0;
        return;
    }
    int mid=(l+r)>>1;
    build(k<<1,l,mid);build(k<<1|1,mid+1,r);
}

void insert(int k,int pos)
{
    if(tr[k].l==tr[k].r && tr[k].l==pos)
    {
        tr[k].sum++;
        tr[k].mn=tr[k].mx=pos;
        return;
    }
    int mid=(tr[k].l+tr[k].r)>>1;
    if(pos<=mid) insert(k<<1,pos);
    if(pos>mid)insert(k<<1|1,pos);
    pushup(k);
}

int query(int k,int l,int r,int flag)
{
    if(tr[k].l==l && tr[k].r==r)
      return flag==1?tr[k].mn:tr[k].mx;
    pushup(k);
    int mid=(tr[k].r+tr[k].l)>>1;
    if(l>mid) return query(k<<1|1,l,r,flag);
    else if(r<=mid) return query(k<<1,l,r,flag);
    else
    {
        if(flag==1) return min(query(k<<1,l,mid,flag),query(k<<1|1,mid+1,r,flag));
        else return max(query(k<<1,l,mid,flag),query(k<<1|1,mid+1,r,flag));
    }
}

int main()
{
    scanf("%d",&n);memset(val,127,sizeof val);
    for(int i=1;i<=n;i++)
    {
        scanf("%d",&a[i]);
        b[i]=a[i];val[i]=a[i];
    }
    sort(b+1,b+n+1);
    tot=unique(b+1,b+n+1)-b-1;
    for(int i=1;i<=n;i++) a[i]=lower_bound(b+1,b+tot+1,a[i])-b,num[a[i]]=i;
    build(1,1,tot);ans=val[1];insert(1,a[1]);
    for(int i=2;i<=n;i++)
    {
        int q=query(1,1,a[i],0);
        int h=query(1,a[i],tot,1);
        if(h==inf)ans+=abs(val[num[a[i]]]-val[num[q]]);
        else ans+=min(abs((val[num[a[i]]]-val[num[q]])),abs((val[num[h]]-val[num[a[i]]])));
        insert(1,a[i]);
    }
    printf("%d
",ans);
}
折花枝,恨花枝,准拟花开人共卮,开时人去时。 怕相思,已相思,轮到相思没处辞,眉间露一丝。
原文地址:https://www.cnblogs.com/L-Memory/p/7356938.html