一、单调栈
例 -- Largest Rectangle in a Histogram:学习了两种写法(思路):按从低到高排列矩形。
(1) ? 栈s里保存的矩形,都是按从低到高排列的,但是新加入一个矩形a[i]后,它可能比现在栈最后加进来的数要大,也可能要小于等于;主要是每个矩形都要按自己的高度来找答案。
①如果大,我们就加入到栈,并给其宽度。
②小于等于,那么前面一些矩形就已经无法按照他们的高度来得到答案了,所以开始统计之前的//因为之后统计的都跟它的高度没关系了。这里要循环,这一小段里的从低到高,宽度是可以共享的,所以widthsum每次循环时,都要加上此刻矩形的宽度。最后+1赋值给新的a[i]的宽度,因为这些还可以“废物利用”~
1 inline long long work() 2 { 3 long long ans=0; 4 for(int i=1;i<=n+1;i++) 5 { 6 if(height[i]>Stack[top]) 7 { 8 Stack[++top]=height[i];width[top]=1; 9 } 10 else 11 { 12 int Widthsum=0; 13 while(Stack[top]>height[i]) 14 { 15 Widthsum+=width[top]; 16 ans=max(ans,(long long)Widthsum*Stack[top]); 17 top--; 18 } 19 Stack[++top]=height[i];width[top]=Widthsum+1; 20 } 21 } 22 return ans; 23 }
(2) 每一个矩形都跟左右有关,它向左右延伸,那么就去找矩形a[i]的左右最大衍生长度。用stack<pair<,> >来存,stl/r是左右距离。上一种如果a[i]比栈顶小,那要重点关注。但是这一种,如果此时栈元素(l.top().first)大于a[i],那么a[i]还可以继续向左边延伸,这个就没用了,所以弹出,只要记录最后比a[i]小的位置就行,然后往栈里放a[i],因为被a[i]顶掉的元素肯定是大于等于它的,那么a[i+1]无论什么情况,都要被a[i]制约(连续),所以没关系,看a[i]就好。最后遍历找答案时,左右相减得到宽度(str-stl-1),乘上高度a[i]就好了
1 ll stl[N],str[N],a[N]; 2 stack<pair<ll,ll> >l,r; //左值右下标 | > >分开一点 3 inline ll findmax() 4 { 5 while(!l.empty()) l.pop(); 6 while(!r.empty()) r.pop(); 7 ll ans=0; 8 l.push({-1,0}),r.push({-1,n+1}); //不用特判 9 for(int i=1;i<=n;i++) 10 { 11 while(l.top().first>=a[i]) l.pop(); 12 stl[i]=l.top().second; 13 l.push(mp(a[i],i)); 14 } 15 for(int i=n;i>=1;i--) 16 { 17 while(r.top().first>=a[i]) r.pop(); 18 str[i]=r.top().second; 19 r.push(mp(a[i],i)); 20 } 21 for(int i=1;i<=n;i++) 22 ans=max(ans,a[i]*(str[i]-stl[i]-1)); 23 return ans; 24 }
二、单调队列
1 inline int FindMax() 2 { 3 int ans=-0x3f3f3f3f; 4 Q.push_back(0); //Q放置的是下标 5 for(int i=1;i<=n;i++) 6 { 7 while(!Q.empty()&&Q.front()<i-m)Q.pop_front(); //判断是否超出左边界 8 ans=max(ans,s[i]-s[Q.front()]); // 不断更新答案 9 while(!Q.empty()&&s[Q.back()]>=s[i])Q.pop_back(); 10 //比右边大的话,减掉一定小于等于零,并不优于i,所以不能要这一块,只能减这块之前的 11 Q.push_back(i); 12 } 13 return ans; 14 }