codeforces 601B 斜率+单调栈

题目意思如下:求区间[l,r]内所有子数组的L(i,j)之和,L(i,j)如题所说。

1、转化题目,将原公式想成两点斜率

2、证明:最大的斜率只会存在于相邻两点

3、题目转化为求一列数a[l..r],求其每个字序列中最大数的的和

4、想到单调栈模型,复杂度O(n*q)

一些陷阱:

1、数据范围:最后答案要用long long

2、计算公式:我用的是ans=sigma(l[i]*r[i]*ne[i])

3、单调栈维护时注意相等的情况

4、单调栈最后里面元素要出栈

代码如下:

#include


using namespace std;


const long long maxn = 1e6+10;

int n,q,l,r;

long long a[maxn],ne[maxn],nel[maxn],ner[maxn];

int stack[maxn];

int top;

long long ans;


int main(int argc, const char * argv[]) {

    cin >> n >> q;

    for (int i=0; i<n; i++) {

        cin >> a[i];

        if (i>0) {

            ne[i] = a[i]-a[i-1];

            //取绝对值

            if(ne[i]<0) ne[i]=-ne[i];

        }

    }

    for (int i=0; i<q; i++) {

        cin >> l>>r;

        //初始化数据

        ans = 0;

        for (int i=l; i<r; i++) {

            nel[i]=1;ner[i]=1;

        }

        top = -1;

        //维护单调栈,记录ne[i]左右比其小的元素个数

        for (int i=l; i<r; i++) {

            while (top>=0&&ne[stack[top]]<ne[i]) {

                if(top>0) ner[stack[top-1]]+=ner[stack[top]];

                nel[i]+=nel[stack[top]];

                stack[top] = -1;

                top--;

            }

            top++;

            stack[top] = i;

        }

        //注意最后栈里元素要出栈

        while (top>0) {

            ner[stack[top-1]]+=ner[stack[top]];

            top--;

        }

        for (int i=l; i<r; i++) {

            ans+=nel[i]*ner[i]*ne[i];

        }

        cout << ans << endl;

    }

    return 0;

}



你可能感兴趣的:(codeforces)