• 单调栈


    单调栈的定义:

    元素顺序始终保持单调性(递增、递减)的栈。
    (递增单调栈和递减单调栈的区别仅限于单调顺序不同,故以下为了方便讲解,默认提到的单调栈都为严格递增单调栈。)

    维护方法:

    压入新元素 (x) 时,将 (x) 与栈顶元素比较,若 (x) 小于等于栈顶元素,则将栈顶元素弹出,再与新的栈顶元素比较,直到 (x) 大于栈顶元素。


    举例:

    有一组数7,8,9,2,10,13,将这6个数从左往右压入严格递增单调栈:
    1、压入7,此时栈为空,无栈顶元素,操作完成后栈内元素为:{7};
    2、压入8,此时栈顶元素为7,7<8,故可以直接压入,操作完成后栈内元素为:{7、8};
    3、压入9,此时栈顶元素为8,8<9,故可以直接压入,操作完成后栈内元素为:{7、8、9};
    4、压入2,此时栈顶元素为9,9>2,故需要弹出栈顶元素9;同理,弹出8、7。此时栈为空,可以压入2,操作完成后栈内元素为:{2};
    5、压入10,此时栈顶元素为2,2<10,故可以直接压入,操作完成后栈内元素为:{2、10};
    6、压入13,此时栈顶元素为10,10<13,故可以直接压入,操作完成后栈内元素为:{2、10、13};
    7、清空栈内元素;

    使用单调栈时,一般是在弹出元素的过程中进行统计操作(即x小于等于栈顶元素的情况);


    例题:

    Largest Rectangle in a Histogram

    题目大意:给定 (n) 个高为 (a_1、a_2、...、a_n) 的柱子,求该柱状图中,可勾勒出的最大的矩形面积。

    思路:选择某个柱子 (i) ,将 (i) 向两边拓展,若碰到比 (a_i) 高的柱子就接着拓展,若碰到比 (a_i) 小的柱子就停止拓展。
    直接暴力做的时间复杂度是 (O(n^2)) ,但可以使用单调栈优化。
    考虑向一个递增单调栈中按 (i) 从小到大的顺序压入 (i) ,设栈顶元素为 (top) ,若 (a_i < a_top) ,则在弹出 (top) 的同时,将答案 (ans)(top) 向左右拓展可得的最大面积取 (Max),并更新第 (i) 根柱子向左端能拓展到的最远处。
    (i) 根柱子向最左端拓展的最远处可以在压入 (i) 之前弹出 (top) 的过程中更新,而最右端则应在弹出 (i) 的时候被更新。

    代码:

    #include <assert.h>
    #include <ctype.h>
    #include <errno.h>
    #include <float.h>
    #include <fstream>
    #include <iomanip>
    #include <iostream>
    #include <limits.h>
    #include <locale.h>
    #include <math.h>
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <time.h>
    #include <wchar.h>
    #include <wctype.h>
    #include <algorithm>
    #include <bitset>
    #include <cctype>
    #include <cerrno>
    #include <clocale>
    #include <cmath>
    #include <complex>
    #include <cstdio>
    #include <cstdlib>
    #include <cstring>
    #include <ctime>
    #include <deque>
    #include <exception>
    #include <fstream>
    #include <functional>
    #include <limits>
    #include <list>
    #include <map>
    #include <iomanip>
    #include <ios>
    #include <iosfwd>
    #include <iostream>
    #include <istream>
    #include <ostream>
    #include <queue>
    #include <set>
    #include <sstream>
    #include <stack>
    #include <stdexcept>
    #include <streambuf>
    #include <string>
    #include <utility>
    #include <vector>
    #include <cwchar>
    #include <cwctype>
    #define int long long
    using namespace std;
    const int N = 8e4 + 5;
    int n, ans, cnt, a[N], stck[N];
    signed main () {
    	scanf ("%lld", &n);
    	for (int i = 1; i <= n; i ++)
    		scanf ("%lld", &a[i]);
    	for (int i = 1; i <= n; i ++) {
    		while (cnt && a[stck[cnt]] <= a[i]) {
    			ans += i - stck[cnt] - 1;
    			cnt --;
    		}
    		stck[++ cnt] = i;
    	}
    	for (int i = 1; i <= cnt; i ++)
    		ans += n - stck[i];
    	printf ("%lld
    ", ans);
    	return 0;
    }
    
  • 相关阅读:
    python文件打开方式详解——a、a+、r+、w+、rb、rt区别
    io.UnsupportedOperation: can't do nonzero cur-relative seeks”错误
    端口三种模式:access,hybrid,trunk
    水仙花数
    maktrans和translate详解
    实战NFS服务搭建与配置
    except 配合 shell实现公钥分发脚本
    linux系统免秘钥分发文件
    rsync + inotify 实现远程实时同步数据
    通过rsync实现全网数据备份检查脚本
  • 原文地址:https://www.cnblogs.com/HarryHuang2004/p/13197446.html
Copyright © 2020-2023  润新知