Feel Good(POJ 2796)树状数组+单调栈

题意:

一排数,找到一个区间,使得该区间内 所有数之和乘以该区间内的最小数 最大,输出该最大值和区间左右端点。

Sample Input

6
3 1 6 4 5 2

Sample Output

60
3 5

 

冉了我好久的一道单调栈的题,毕竟我也是刚入门。

注意的一点:ans初值要赋为-1,如果默认赋为0,当我们的数据最大值为0时就无法操作

 

代码如下:

#include<stdio.h>
#include<algorithm>
#include<string.h>
using namespace std;
const int MX=1e5+100;
int n;
long long a[MX],bit[MX],L[MX],R[MX],stk[MX],top;

int lowbit(int x){
    return x&-x;
}

void update(int x,int add)
{
    for(;x<=n;x+=lowbit(x))
        bit[x]+=add;
}

long long sum(int x)
{
    long long tot=0;
    for(;x;x-=lowbit(x))
        tot+=bit[x];
    return tot;    
}

void sol()
{
    while(top>0) top--;
    for(int i=1;i<=n;++i)
    {
        while(top>0 && a[i]<=a[stk[top]]) top--;
        if(top==0)  L[i]=0;
        else        L[i]=stk[top];
        stk[++top]=i;                 
    }
    
    while(top>0) top--;
    for(int i=n;i>=1;--i)
    {
        while(top>0 && a[i]<=a[stk[top]]) top--; 
        if(top==0)  R[i]=n+1;
        else        R[i]=stk[top];
        stk[++top]=i;
    }
}

long long bin(int l,int r)
{
    return sum(r)-sum(l-1);
}

int main()
{
    while(scanf("%d",&n)!=EOF)
    {
        memset(bit,0,sizeof(bit));
        for(int i=1;i<=n;++i)
        {
            scanf("%d",&a[i]);
            update(i,a[i]);
        }
    
        sol();
        long long ans=-1;
        int l,r;
        for(int i=1;i<=n;++i)
        {
            long long t=bin(L[i]+1,R[i]-1)*a[i];
            if(t>ans)
            {
                ans=t;
                l=L[i]+1;
                r=R[i]-1;
            }
        }
        printf("%lld\n%d %d\n",ans,l,r);
    }
    return 0;
}
/*
6
3 1 6 4 5 2
*/

 

posted @ 2018-07-31 20:30  qseer  阅读(167)  评论(0编辑  收藏  举报