单调栈 & 单调队列

一、单调栈

 例 -- 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 }
学长教ヾ(•ω•`)o

 

 

二、单调队列

 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 }

 

posted @ 2019-07-13 10:26  XXrl  阅读(166)  评论(0编辑  收藏  举报