1. 程式人生 > 其它 >【AcWing】131. 直方圖中最大的矩形

【AcWing】131. 直方圖中最大的矩形

題鏈

單調棧非常好的講解

簡單易懂

利用單調棧:尋找比p[i]小的下一個值的位置和上一個值的位置;

#include<bits/stdc++.h> 
using namespace std;
#define ll long long 
#define LL long long 
#define MS 3000009

LL n,m;
stack<LL > sta;
LL ans;
struct node{
	int l,r;
	LL val;
}p[MS];

void solve(){
	p[n+1] = p[0] = {0,0,-1};
	for(int i=1;i<=n+1;i++){ // 尋找 p[i] 後第一個比 p[i] 小的位置 
		if(sta.empty() || p[sta.top()].val <= p[i].val) sta.push(i);
		else{
			while(!sta.empty() && p[sta.top()].val > p[i].val){
				int t = sta.top();
				sta.pop();
				p[t].r = i-1;
			}
			sta.push(i);
		}
	}
	while(!sta.empty()) sta.pop();
	for(int i=n;i>=0;i--){ // 尋找 p[i] 前第一個比 p[i] 小的位置 
		if(sta.empty() || p[sta.top()].val <= p[i].val) sta.push(i);
		else{
			while(!sta.empty() && p[sta.top()].val > p[i].val){
				int t = sta.top();
				sta.pop();
				p[t].l = i+1;
			}
			sta.push(i);
		}
	}
	while(!sta.empty()) sta.pop();
	// getans 
	LL ans = 0;
	for(int i=1;i<=n;i++){
		ans = max(ans ,p[i].val*(p[i].r-p[i].l+1));
	}
	cout << ans << "\n";
}

int main(){
	ios::sync_with_stdio(false);
	while(cin >> n && n){
		for(int i=1;i<=n;i++){
			cin >> p[i].val;
			p[i].l = p[i].r = i;
		}
		solve();
		
	}
	

	return 0;
}

小小優化

#include<bits/stdc++.h> 
using namespace std;
#define ll long long 
#define LL long long 
#define MS 3000009

LL n,m;
LL p[MS];
stack<LL > sta;
LL ans;

void solve(){
	ans = 0;
	p[++n] = -1;
	for(int i=1;i<=n;i++){
		if(sta.empty() || p[sta.top()] <= p[i]){
			sta.push(i);
		}
		else{
			LL t;
			while(!sta.empty() && p[sta.top()] > p[i]){
				t = sta.top();
				sta.pop();
				ans = max(ans ,(i-t)*p[t] );  
			}
			// 由於p[i]這個值左邊可能向左擴充套件
			// 所以直接將i的位置改到它能擴充套件的最左位置
			// 這樣求面積遍歷陣列只要從左到右一遍過 
			sta.push(t); 
			p[t] = p[i];
		}
	}
	while(!sta.empty()) sta.pop();
	cout << ans << "\n";
}

int main(){
	ios::sync_with_stdio(false);
	while(cin >> n && n){
		for(int i=1;i<=n;i++){
			cin >> p[i];
		}
		solve();
	}
	

	return 0;
}