單調棧詳解 + poj 2796 poj 2559 CF 547B
單調棧:
定義:用棧結構來實現,使得遍歷陣列中棧頂元素保持一定範圍的最大或最小,並且棧中元素始終保持單調性的棧。
功能:用以快速(O(n))求出陣列中某連續子集中的最大值或者最小值。
原理:
以求某連續子集中的最小值為例:
假設某陣列為:
下標 | 1 | 2 | 3 | 4 | 5 | 6 |
元素 | 3 | 1 | 6 | 4 | 5 | 2 |
模擬過程:
棧頂下標表示當前元素為從此下標到 上一個棧頂下標的最小值。
1.棧為空,將3的下標壓入棧中。 //當前棧狀態:(棧底 0)1 (棧頂)
2.元素1 <= 3,所以3的下標出棧,1的下標入棧。 //當前棧狀態:(棧底 0)2 (棧頂)
3.元素1 < 6,6的下標入棧。 //當前棧狀態:(棧底 0) 2 3 (棧頂) 此時表示6為 2 + 1 到 3 的最小值。
4.元素4 <= 6,6的下標出棧,1 < 4,4的下標入棧。 //當前棧狀態:(棧底0)2 4 (棧頂) 此時表示4為 2 + 1 到 4的最小值。
5.元素4 < 5,5的下標入棧。 //當前棧狀態:(棧底0)2 4 5 (棧頂) 此時表示5為 4 + 1 到 5的最小值。
6.元素2 < 5, 5的下標出棧,2<4,4的下標出棧,2的下標入棧。 //當前棧狀態:(棧底0)2 6 (棧頂) 此時表示2為 2 + 1 到 6的最小值。
7.更新完畢。
整個過程,每出棧一次記錄一次,就可以記錄下整個過程中某個連續子段的最小值,達到了其功能。
以下為例題。
poj 2796:
題意:
1e6的資料向量,求連續的子集的和與子集中最小的數的積的最大值, 並求出這段子集的左右座標。
解析:
不造為啥用stack的stl錯了,用陣列的過了。
這題有兩個注意的點,一個是開始ans置為-1,不然會wa的很慘很慘,因為ans = 0 的時候也更新ansL, ansR。
另一個就是要把-1的節點插入到陣列最後,以便單調棧遍歷完整個陣列。
棧頂為當前的最小值。
程式碼:
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <algorithm>
#include <cstring>
#include <cmath>
#include <stack>
#include <vector>
#include <queue>
#include <map>
#include <climits>
#include <cassert>
#define LL long long
#define lson lo, mi, rt << 1
#define rson mi + 1, hi, rt << 1 | 1
using namespace std;
const int maxn = 1e5 + 10;
const int inf = 0x3f3f3f3f;
const double eps = 1e-8;
const double pi = acos(-1.0);
const double ee = exp(1.0);
LL a[maxn];
LL sum[maxn];
int s[maxn];
int main()
{
#ifdef LOCAL
freopen("in.txt", "r", stdin);
#endif // LOCAL
int n;
while (~scanf("%d", &n))
{
memset(sum, 0, sizeof(sum));
for (int i = 1; i <= n; i++)
{
scanf("%lld", &a[i]);
sum[i] += sum[i - 1] + a[i];
}
a[++n] = -1;///debug
LL ans = -1;///debug
int ansL = -1, ansR = -1;
int top = 0;
for (int i = 1; i <= n; i++)
{
while (top && a[i] <= a[s[top]])
{
LL t = a[s[top]] * (sum[i - 1] - sum[s[top - 1] + 1 - 1]);
if (ans < t)
{
ans = t;
ansL = s[top - 1] + 1;
ansR = i - 1;
}
top--;
}
s[++top] = i;
}
printf("%lld\n%d %d\n", ans, ansL, ansR);
}
return 0;
}
poj 2559:
題意:
如上圖,給一些寬度為1的矩形的高度,求由矩形圍成的大矩形的最大面積。
資料量1e5。
解析:
找每個範圍中的最小高度,此時這個最小高度作為整個範圍的高,計算面積,掃一遍取最大面積即可。
往前掃一遍,後掃一遍,相當於記錄當前這個點a[i]在哪個區域內始終是最小的。
注意的是後掃的時候,要將棧頂置為-1,否則後掃時棧值無法置為n+1。
比如 5 0 0 0 0 1,這組資料。
程式碼:
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <algorithm>
#include <cstring>
#include <cmath>
#include <stack>
#include <vector>
#include <queue>
#include <map>
#include <climits>
#include <cassert>
#define LL long long
#define lson lo, mi, rt << 1
#define rson mi + 1, hi, rt << 1 | 1
using namespace std;
const int maxn = 1e5 + 10;
const int inf = 0x3f3f3f3f;
const double eps = 1e-8;
const double pi = acos(-1.0);
const double ee = exp(1.0);
LL a[maxn];
int s[maxn];//stack
int pre[maxn];
int las[maxn];
int main()
{
#ifdef LOCAL
freopen("in.txt", "r", stdin);
#endif // LOCAL
int n;
while (~scanf("%d", &n) && n)
{
memset(s, 0, sizeof(s));
for (int i = 1; i <= n; i++)
{
scanf("%lld", &a[i]);
}
int top = 0;
a[0] = -1;
for (int i = 1; i <= n; i++)
{
while (top && a[i] <= a[s[top]])
{
top--;
}
pre[i] = s[top];
s[++top] = i;
}
top = 0;
s[top++] = n + 1;
a[n + 1] = -1;
for (int i = n + 1; i >= 1; i--)
{
while (top && a[i] <= a[s[top]])
{
top--;
}
las[i] = s[top];
s[++top] = i;
}
LL ans = 0;
for (int i = 1; i <= n; i++)
{
// cout << pre[i] << " " << las[i] << endl;
LL t = (las[i] - pre[i] - 1) * a[i];
if (ans < t)
ans = t;
}
printf("%lld\n", ans);
}
return 0;
}
CF 547B:
題目:
Description
Mike is the president of country What-The-Fatherland. There are n bears living in this country besides Mike. All of them are standing in a line and they are numbered from1 ton from left to right.i-th bear is exactlyai feet high.
A group of bears is a non-empty contiguous segment of the line. The size of a group is the number of bears in that group. The strength of a group is the minimum height of the bear in that group.
Mike is a curious to know for each x such that1 ≤ x ≤ n the maximum strength among all groups of sizex.
Input
The first line of input contains integer n (1 ≤ n ≤ 2 × 105), the number of bears.
The second line contains n integers separated by space,a1, a2, ..., an (1 ≤ ai ≤ 109), heights of bears.
Output
Print n integers in one line. For each x from 1 to n, print the maximum strength among all groups of size x.
Sample Input
Input10 1 2 3 4 5 4 3 2 1 6Output
6 4 4 3 3 2 2 1 1 1
題意:
給n個數,找到長度為1 ~ n 的子集中,每個子集中元素的最小值,然後取代表每個子集的最小值的最大值。
解析:
如上題一樣,前後掃一遍,相減出長度。
然後掃一遍就好啦。
感謝這題讓我認識了單調棧!
這題有個要注意的地方:
所有長度掃完之後要做一個下面的更新:
for (int i = n - 1; i >= 1; i--)
{
maxValue[i] = max(maxValue[i + 1], maxValue[i]);
}
因為有可能一些長度是取不到的,所以醬紫更新一下就行了。程式碼:
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <algorithm>
#include <cstring>
#include <cmath>
#include <stack>
#include <vector>
#include <queue>
#include <map>
#include <climits>
#include <cassert>
#define LL long long
#define lson lo, mi, rt << 1
#define rson mi + 1, hi, rt << 1 | 1
using namespace std;
const int maxn = 2e5 + 10;
const int inf = 0x3f3f3f3f;
const double eps = 1e-8;
const double pi = acos(-1.0);
const double ee = exp(1.0);
int a[maxn];
int pre[maxn], las[maxn];
int maxValue[maxn];
int main()
{
#ifdef LOCAL
freopen("in.txt", "r", stdin);
#endif // LOCAL
int n;
scanf("%d", &n);
for (int i = 1; i <= n; i++)
{
scanf("%d", &a[i]);
}
stack<int> s;
s.push(0);
for (int i = 1; i <= n; i++)
{
while (!s.empty() && a[i] <= a[s.top()])
s.pop();
pre[i] = s.top();
s.push(i);
}
stack<int> t;
t.push(n + 1);
for (int i = n; i >= 1; i--)
{
while (!t.empty() && a[i] <= a[t.top()])
{
t.pop();
}
las[i] = t.top();
t.push(i);
}
for (int i = 1; i <= n; i++)
{
// cout << pre[i] << " " << las[i] << endl;
int len = las[i] - pre[i] - 1;
maxValue[len] = max(maxValue[len], a[i]);
}
for (int i = n - 1; i >= 1; i--)
{
maxValue[i] = max(maxValue[i + 1], maxValue[i]);
}
for (int i = 1; i <= n; i++)
{
printf("%d ", maxValue[i]);
}
return 0;
}
相關推薦
單調棧詳解 + poj 2796 poj 2559 CF 547B
單調棧: 定義:用棧結構來實現,使得遍歷陣列中棧頂元素保持一定範圍的最大或最小,並且棧中元素始終保持單調性的棧。 功能:用以快速(O(n))求出陣列中某連續子集中的最大值或者最小值。 原理: 以求某連續子集中的最小值為例: 假設某陣列為: 下標 1 2 3 4 5 6 元
『單調棧與單調佇列詳解』
單調棧 性質 單調棧是一種特殊的棧,特殊之處在於棧內的元素都保持一個單調性,可能為單調遞增,也可能為單調遞減。 模型 例如下圖就是一個單調遞增的單調棧。 其中的元素從小到大排列。 那麼,如果我們要加入一個新的元素5,5>4,符合要求,就可以直接加入。
JVM 虛擬機器棧詳解
棧幀 棧幀 (Stack Frame) 是用於支援虛擬機器進行方法呼叫和方法執行的資料結構,它是虛擬機器執行時資料區中的虛擬機器棧 (Virtual Machine Stack)的棧元素 。棧幀儲存了方法的區域性變量表、運算元棧、動態連線和方法返回地址等資訊。每一個方能從
雜談——TCP/IP 協議棧詳解
說到協議棧,我們就先來看看它的定義是什麼。 TCP/IP 協議棧是一系列網路協議的總和,是構成網路通訊的核心骨架,它定義了電子裝置如何連入因特網,以及資料如何在它們之間進行傳輸。 本帥博主之前寫過一篇關於OSI模型的部落格,OSI模型採用
JVM記憶體劃分(堆、棧詳解)
前言 我們知道,Java的記憶體管理是由JVM虛擬機器來控制的,作為Java程式開發者不需要像C、C++的開發人員一樣對記憶體進行管理,這大大降低了開發的複雜度。但隨之而來的問題是,一旦出現記憶體洩漏和溢位方面的問題,如果不瞭解虛擬機器是如何使用記憶體的,那麼排查錯誤將會變得很困
IPFS協議棧詳解-身份層
當我們剛安裝好ipfs,第一次使用的時候,我們首先得輸入: ipfs init 這個命令的作用我們之前講過,就是建立一個ipfs節點,我們可以在當前目錄看到一個.ipfs的資料夾,就是節點資料夾。我們可以檢視該資料夾下config檔案,看到節點的id和祕鑰,以及節點的大小等預設屬性。或者也
TCP/IP協議棧詳解
TCP/IP協議棧 TCP/IP協議是規範不同主機之間進行通訊的一系列協議,其中涉及到資料的封裝,傳輸,定址等一系列內容,是計算機領域非常重要的基礎知識,我們在Java中用到的Socket通訊就是基於TCP/IP協議中的TCP協議,開發為一系列封裝好的API供使用者使用。為什麼要制定這些
值棧詳解(ValueStack)
什麼是值棧 之前web階段,在servlet裡面進行操作,把資料放到域物件裡面,在頁面中使用el表示式獲取到。域物件在一定範圍內,存值和取值。 在struts2裡面提供了本身的一種儲存機制,類似於域物件,是值棧,可以存值和取值。 在action裡面把資料
【虛擬機器棧】虛擬機器棧詳解
前言Java 虛擬機器的記憶體模型分為兩部分:一部分是執行緒共享的,包括 Java 堆和方法區;另一部分是執行緒私有的,包括虛擬機器棧和本地方法棧,以及程式計數器這一小部分記憶體。JVM 是基於棧的。但是這個“棧” 具體指的是什麼?難道就是虛擬機器棧?想要回答這個問題我們先要
Struts2的值棧詳解
ssh中頁面和action之間資料儲存和傳遞有多種方式,URL傳值,模型驅動,表單傳值,以及我們本文要介紹的值棧等。每種方式都有它的特點和適用範圍,小編根據自身的適用經驗和網上的查
堆和棧詳解
對堆疊在程式中的作用有更深入的瞭解。不同的語言有不同的函式呼叫規定,這些因素有引數的壓入規則和堆疊的平衡。windows API的呼叫規則和ANSI C的函式呼叫規則是不一樣的,前者由被調函式調整堆疊,後者由呼叫者調整堆疊。兩者通過“__stdcall”和“__cdecl”字首區分。先看下面這段程式碼:
函式呼叫過程中函式棧詳解
當程序被載入到記憶體時,會被分成很多段 程式碼段:儲存程式文字,指令指標EIP就是指向程式碼段,可讀可執行不可寫,如果發生寫操作則會提示segmentation fault 資料段:儲存初始化的全域性變數和靜態變數,可讀可寫不可執行 BSS:未初始化的全域性變數
HDOJ 3530 Subsequence(單調佇列(含單調佇列詳解))
我們從最簡單的問題開始:給定一個長度為N的整數數列 a [ i ] , i = 0, 1 , . .. , N-1 和區間長度k.要求: f ( i ) = max { a ( i - k + 1 ) , a ( i - k + 2 ) , . .. , a ( i ) } , i = 0 ,
Android之Fragment回退棧詳解
前言:本文將結合開發中的實際需求,來講解一下Fragment中的回退棧 對於Activity,當按返回鍵時,能夠返回到上一個Activity,但是,當我們Fragment到Activity中時,如果不做任何處理,當按返回鍵時,當前Fragment都會全部退出,如
POJ 2559 Largest Rectangle in a Histogram(單調棧)
common pst locale str flow bold text function target 【題目鏈接】:click here~~ 【題目大意】: A histogram is a polygon composed of a sequence of
POJ-2559 Largest Rectangle in a Histogram(單調棧)
comm pict mon include max specified out names align Largest Rectangle in a Histogram Time Limit: 1000MS Memory Limit: 65536K Tota
51nod 1215 數組的寬度&poj 2796 Feel Good(單調棧)
close queue fin click nod stream ++ std tchar 單調棧求每個數在哪些區間是最值的經典操作。 把數一個一個丟進單調棧,彈出的時候[st[top-1]+1,i-1]這段區間就是彈出的數為最值的區間。 poj2796 彈
POJ - 2559 單調棧
相對 全部 top stl ans clas body 延伸 bre 算是回顧吧 掃描計算時的高度是單調遞減的, 最相對較高的能延伸的矩陣[全部]計算完以後都合並成一個待計算的相對較矮的單一矩陣 規定合並後的矩陣留到下一次計算 一直掃描到棧空(哨兵h[n+1]==0處)即可
題解報告:poj 2559 Largest Rectangle in a Histogram(單調棧)
++i char test case c代碼 ams pac 分享圖片 cas ram Description A histogram is a polygon composed of a sequence of rectangles aligned at a common
10.30 poj 2559 單調棧
https://blog.csdn.net/zuzhiang/article/details/78135142 http://poj.org/problem?id=2559 my code_1 solution 1 #include<iostream> #include&