单调队列和单调栈

数据结构

题目描述

创建一种结构,完成下列五种功能:

I x 在当前位置插入 x 元素;
D 删除当前位置的元素;
L 将当前位置左移一位,除非它已经是第一个元素;
R 将当前位置右移一位,除非它已经是最后一个元素;
Q k 在当前位置之前,找到一个最大的 Si(1≤i≤k,Si=a1+a2+…+ai)

代码实现

#include <iostream>
#include <string>
#include <algorithm>
#include <cstdio>
#include <vector>
#include <cstdlib>
#include <cinttypes>
#include <stack>
using namespace std;
 
class NewStruct{
public:
    NewStruct() {
        sum[0] = 0;
        ans[0] = INT64_MIN;
    }
    void insert(long long x);
    void del();
    void move_left();
    void move_right();
    long long query(long long k);
private:
    stack<long long> s1, s2;
    long long sum[1005];
    long long ans[1005];
};

void NewStruct::insert(long long x) {
    s1.push(x);
    int ind = s1.size();
    sum[ind]= x + sum[ind - 1]; 
    ans[ind] = max(ans[ind - 1], sum[ind]);
    return ;
}

void NewStruct::del() {
    if (s1.empty()) return ;
    s1.pop();
    return ;
}

void NewStruct::move_left(){
    if (s1.empty()) return;
    s2.push(s1.top());
    del();
    return ;
}

void NewStruct::move_right(){
    if (s2.empty()) return ;
    insert(s2.top());
    s2.pop();
    return ;
}

long long NewStruct::query(long long k) {
    return ans[k];
}

int main() {
    long long n;
    cin >> n;
    string op;
    long long  val;
    NewStruct s;
    for (int i = 0; i < n; i++) {
        cin >> op;
        switch(op[0]) {
            case 'I': {
                cin >> val;
                s.insert(val);
            } break;
            case 'D': {
                s.del();
            } break;
            case 'L': {
                s.move_left(); 
            }break;
            case 'R': {
                s.move_right();
            } break;
            case 'Q': {
                cin >> val;
                cout << s.query(val) << endl;
            } break;
        }
    }
 
    return 0;
}

单调队列

题目描述
​ 给出一个长度为 N 的数组,一个长为 K 的滑动窗口从最左移动到最右,每次窗口移动,如下图
在这里插入图片描述

  1. 本质问题是:固定查询结尾的 RMQ 问题,例如 R M Q ( x , 7 ) RMQ(x, 7) RMQ(x,7)
  2. 问题性质:维护滑动窗口最值问题
  3. 入队:将队尾违反单调性的元素淘汰出局,再将当前元素入队
  4. 出队:如果队首元素超出了滑动窗口的范围,队首出队
  5. 队首元素:滑动窗口内的最值
  6. 均摊时间复杂度: O ( 1 ) O(1) O(1)

代码实现

#include<iostream>
#include<cstring>
#include<algorithm>
#include<cstdio>
#include<queue>
#include<vector>
using namespace std;
#define MAX_N 300000
int q[MAX_N + 5], head = 0, tail = 0;
int val[MAX_N + 5];

int main() {
    int n, k;
    cin >> n >> k;
    for (int i = 1; i <= n; i++) {
        cin >> val[i];
    }

    for (int i = 1; i <= n; i++) {
        while(tail - head && val[q[tail - 1]] > val[i]) --tail;
        q[tail++] = i;
        if (q[head] <= i - k) head++;

        if (i >= k) {
            i > k && cout << " ";
            cout << val[q[head]];
        }
    }
    cout << endl;
    head = tail = 0;
    for (int i = 1; i <= n; i++) {
        while (head - tail && val[q[tail - 1]] < val[i]) --tail;
        q[tail++] = i;
        if (q[head] <= i - k) head += 1;
        if (i >= k) {
            i > k && cout << " ";
            cout << val[q[head]];
        } 
    }
    cout << endl;
    return 0;
}

单调栈

  1. 单调栈保留了单调队列的『⼊队』操作
  2. 单调栈依然是维护了⼀种单调性
  3. 问题性质:最近(⼤于/⼩于)关系
  4. ⼊栈之前,符合单调性的栈顶元素,就是我们要找的最近(⼤于/⼩于)关系
  5. 均摊时间复杂度: O ( 1 ) O(1) O(1)
    题目描述
    ​ 给定从左到右多个矩形,已知这此矩形的宽度都为 1,长度不完全相等。这些矩形相连排成一排,求在这些矩形包括的范围内能得到的面积最大的矩形,打印出该面积。所求矩形可以横跨多个矩形,但不能超出原有矩形所确定的范围。

在这里插入图片描述
代码实现

#include<iostream>
#include<cstring>
#include<algorithm>
#include<cstdio>
#include <stack>
#include<queue>
#include<vector>
using namespace std;
#define MAX_N 100000
long long s[MAX_N + 5], top;
long long h[MAX_N + 5], n;
long long l[MAX_N + 5], r[MAX_N + 5];

void read() {
    scanf("%lld", &n);
    for (long long i = 1; i <= n; i++) scanf("%lld", h + i);
    return ;
}

long long solve() {
    h[0] = h[n + 1] = -1;
    top = -1;
    s[++top] = 0;
    for (long long i = 1; i <= n; i++) {
        while(top != -1 && h[s[top]] >= h[i]) --top;
        l[i] = s[top];
        s[++top] = i;
    }
    top = -1;
    s[++top] = n + 1;
    for (long long i = n; i >= 1; i--) {
        while(top != -1 && h[s[top]] >= h[i]) --top;
        r[i] = s[top];
        s[++top] = i;

    }

    long long ans = 0;
    for (long long i = 1; i <= n; i++) {
        ans = max(ans, h[i] * (r[i] - l[i] - 1));
    }
    return ans;
}

int main() {
    read();
    cout << solve() << endl;
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值