单调栈 单调队列 和 优先队列的应用

#include
using namespace  std;
const int maxn = 1e5 + 10;
struct node{
    long long num;
    int pos;
};
node a[maxn];
long long sum[maxn] = {0};
int main(){
    int n;
    scanf("%d",&n);
    int l = 1;
    int r = n;
    long long ans = 0;
    for(int i = 1;i <= n; ++ i){
        scanf("%lld",&a[i].num);
        sum[i] = sum[i - 1] + a[i].num;
        a[i].pos = i;
    }
    stack  st;
    for(int i = 1;i <= n; ++ i){
        if(st.empty()){
            st.push(a[i]);
            continue;
        }
        while(!st.empty() && 
st.top().num >= a[i].num){
            node u = st.top();
            st.pop();
            int j;
            if(!st.empty())
                j = st.top().pos;
            else{
                j = 0;
            }
            long long temp = 
(sum[i - 1] - sum[j]) * u.num;
            if(temp > ans){
                ans = temp;
                l = j + 1;
                r = i - 1;
            }
//            cout << temp << endl;
        }
        st.push(a[i]);
    }
    int rr = n,ll = 1;
    while(!st.empty()){
        node u = st.top();
        st.pop();
        if(st.empty()){
            ll = 0;
        }
        else{
            ll = st.top().pos;
        }
        long long temp =
 (sum[rr] - sum[ll]) * u.num;
        if(temp > ans){
            ans = temp;
            l = ll + 1;
            r = rr;
        }
//        cout << temp << endl;
    }
    printf("%lld\n%d %d\n",ans,l,r);
    return 0;
}

question 1:给你n个正数一个区间的权值定义为这个区间的所有数之和乘以这个区间内最小的数求所有区间中权值最大的区间。

solve : 对于这个题目我们不难想到要看每一个数作为最小值(或者最大值)的最长的区间是什么,对于这一类问题我们可以考虑用单调栈或者单调队列 用单调递减栈维护一下每次每个数的最大影响区间就是栈的前一个数到下一个要使得这个数出栈的位置。可以将栈中的每一个数看做一堵墙过了这个墙最小值就变成了墙上的这个数。
5
3 6 100 9 15
10000
3 3


基本数据结构的应用一 栈和队列
单调栈 单调队列 和 优先队列的应用

1.单调栈
单调栈是指一个栈内部的元素是具有严格单调性的一种数据结构,分为单调递增栈和单调递减栈。

单调栈有两个性质
1.满足从栈顶到栈底元素具有严格的单调性
2.满足栈的后进先出特性越靠近栈底的元素越早进栈


元素进栈过程
对于一个单调递增栈来说 若当前进栈的元素为 a 如果a < 栈顶元素则直接将a 进栈 如果 a >= 当前栈顶元素则不断将栈顶元素出栈知道满足 a < 栈顶元素
模拟一个数列构造一个单调递增栈
进栈元素分别为3,4,2,6,4,5,2,3。
首先 3 进栈 变为 {3};
然后 4进栈先让3出栈再进栈变为{4};
2 进栈 变为 {4,2};
对于 6 先让 4,2 出栈 再让 6 进栈 {6};
4 进栈 {6,4};
让4 出栈 5进栈 {6,5};
然后2进 2出 3进 变为 {6,5,3};
由于单调栈只对栈顶位置进行操作所以一般应用于只有对数组有一边有限制的地方

实现用STL的栈实现即可 模拟栈也行

2. 单调队列
单调队列是指一个队列内部的元素具有严格单调性的一种数据结构,分为单调递增队列和单调递减队列。

单调队列满足两个性质
1.单调队列必须满足从队头到队尾的严格单调性。
2.排在队列前面的比排在队列后面的要先进队。

元素进队列的过程
对于单调递增队列,对于一个元素a 如果 a > 队尾元素 那么直接将a扔进队列 如果 a <= 队尾元素 则将队尾元素出队列 知道满足 a 大于队尾元素即可;

实现用 stl 的双端队列即可。

由于双端队列即可以在队头操作也可以在队尾操作那么这样的性质就弥补了单调栈只能在一遍操作的不足可以使得其左边也有一定的限制。

单调栈那题,左往右扫,得每个点最左控制到哪,每遇到一点比当前栈顶更大,就连下标打入栈里,此点控制的左界为栈顶元素下标+1,如果比栈顶小,栈顶弹出继续比较栈顶,直至找到比其大,然后同上一种情况。(由于栈是单调的,所以可以直接二分得到其该插入到栈中的位置。。更准确地,应该说是该弹出多少个栈顶)

模板题中往右扫的同时顺便记录了右界,应该说是直接更新答案,一见求和反应用前缀和 

你可能感兴趣的:(ACM笔记-3图流)