栈(poj 2559)

来源:互联网 发布:手机怎么修改mac地址 编辑:程序博客网 时间:2024/05/29 02:29

总结一下栈在序列上的某些应用.

它的结构自然是不必说的,这里只是总结一下他在处理单调性问题方面的应用.
1. 大于 i 的序列段

给你一些宽度为1的直方图,每一个的高为 $h_i$ 问你这些直方图所覆盖的最大面积是多少.题目的详细描述参见[poj 2559](http://poj.org/problem?id=2559)一种简单的方法是对每个 $h_i$ 枚举覆盖住 $h_i$的左端点 $L_i$ 及右端点 $R_i$.这样做需要 $O(n^2)$ .显然是行不通的,注意观察,我们要找的 $L_i,R_i$ 满足以下等式.$$    L_i = min_{j|j<=i}\{h_j\ge h_i\ ,h_k\ge h_i(j<k<i)\};\\    R_i = max_{j|j>=i}\{h_j\ge h_j,\ h_k\ge h_i(i<k<j)\}    $$因此我们可以用栈来优化.用以下操作.对于第 $i$ 项来说,我们维护前 $i$项组成的栈序列,如果 $h_i\le h[st[size-1]]$ 那么,我们让这个值出栈,当栈为空或者不能出栈时,说明栈中的当前元素已经到恰好小于它了.令$L_i = st[size-1]+1,st[size++] = i$ .我们现在来看看出栈的元素.出栈的元素显然都大于当前的第 $i$ 项,这个关系是可以传递的,也就是说在栈中,相临的两项 $st[i],st[i+1]$ 之间如果缺类一些元素 $j,即st[i]<j<st[i+1]$,那么我们可以知道, $h_j\ge h[st[i+1]]$,因此如果下次 $st[i+1]$ 出栈,那么 这些 $j$一定会出栈,这样就减少了重复计算.也就是说对于每个元素来说只会进栈和出栈一次,因此这个算法是 $O(n)$ 的.

AC code

#include <string>#include <cstdio>#include <cstring>#include <map>#include <queue>#include <algorithm>#include <iostream>using namespace std;typedef long long LL;const int maxn = 1e5+10;int n;int a[maxn];int L[maxn];int R[maxn];//栈int stack[maxn];LL solve(){  int s =0,t =0;  //计算L  for(int i=0 ; i<n ; ++i){    while (t>0 && a[stack[t-1]]>=a[i])t--;    L[i] = t==0?0:(stack[t-1]+1);    stack[t++] = i;  }  //计算R  t=0;  for(int i=n-1 ; i>=0 ; i--){    while (t>0 && a[stack[t-1]]>=a[i]) t--;    R[i] = t==0?n-1:(stack[t-1]-1);    stack[t++] = i;  }  LL ans=0;  for(int i=0 ; i<n;  ++i){    ans = max(ans,(LL)a[i]*(R[i]-L[i]+1));  }  return ans;}int main(){    while (scanf("%d", &n)&& n) {      for(int i=0 ; i<n ; ++i)scanf("%d",&a[i] );      std::cout << solve() << '\n';    }    return 0;}
0 0
原创粉丝点击