单调栈&单调队列入门

Posted mxang

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了单调栈&单调队列入门相关的知识,希望对你有一定的参考价值。

此文持续更新。

啊今下午形势政策看看了

技术图片

这个东西,发现我要想好好施展几何得先精通单调栈单调队列。

然后就计划刷刷水题。结果打了一晚上游戏。

又认识了一个辅助妹子,难道我的过去要被画上句号,开始一段新的恋情了吗?还记得两年前,也是那样一个普通的夜晚,也是小炮和露露,

我的小炮特别浪,总是喜欢w跳脸,但她却总是能跟上我,在我跳脸的时候击飞别人,被控的时候坩埚秒解,被追的时候预判救赎,要死的时候闪现给盾,

然而到了后来,我在说什么啊??? 

完蛋了啊,要被队友捅死了啊。

 

poj2796 

定义一段区间的权值为最小值乘以区间和,求给定数组的最大权值。

找到以每个数为最小值的区间的端点。

技术图片
 1 #include <cstdio>
 2 #include <iostream>
 3 using namespace std;
 4 typedef long long ll;
 5 const int N = 1e5+5;
 6 ll n,a[N],pre[N],las[N],sum[N],q[N];
 7 int main(){
 8     scanf("%lld",&n);
 9     for(int i=1;i<=n;i++)scanf("%lld",&a[i]),sum[i]=sum[i-1]+a[i];
10     int l=0,r=0;
11     for(int i=1;i<=n;i++){
12         while (r>0&&a[q[r]]>a[i]){
13             las[q[r]]=i-1;
14             r--;
15         }
16         q[++r]=i;
17     }
18     while (r>0)las[q[r--]]=n;
19     for(int i=n;i>=1;i--){
20         while (r>=0&&a[q[r]]>a[i]){
21             pre[q[r]]=i+1;
22             r--;
23         }
24         q[++r]=i;
25     }
26     while (r>0)pre[q[r--]]=1;
27     ll ans = 0;
28     for(int i=1;i<=n;i++){
29         if(a[i]*(sum[las[i]]-sum[pre[i]-1])>=ans)
30             ans = a[i]*(sum[las[i]]-sum[pre[i]-1]),l=pre[i],r=las[i];
31     }
32     printf("%lld\\n%d %d",ans,l,r);
33 }
View Code

poj 3494 

给01矩阵,找最大的全是1的子矩阵

枚举行,转化成直方图最大矩形面积。

技术图片
 1 #include <cstdio>
 2 #include <cstring>
 3 #include <algorithm>
 4 using namespace std;
 5 int n,m,a[2019][2019],cpp[2009][2009],q[2009],las[2009],pre[2009];
 6 int slove(int a[]){
 7     memset(las,0, sizeof(las));
 8     memset(pre,0, sizeof(pre));
 9     int l=0,r=0;
10     for(int i=1;i<=m;i++){
11         while (r>0&&a[q[r]]>a[i]){
12             las[q[r]]=i-1;
13             r--;
14         }
15         q[++r]=i;
16     }
17     while (r>0)las[q[r--]]=m;
18     for(int i=m;i>=1;i--){
19         while (r>=0&&a[q[r]]>a[i]){
20             pre[q[r]]=i+1;
21             r--;
22         }
23         q[++r]=i;
24     }
25     while (r>0)pre[q[r--]]=1;
26     int ans = 0;
27     for(int i=1;i<=n;i++)if(a[i]*(las[i]-pre[i]+1)>ans)ans = a[i]*(las[i]-pre[i]+1);
28     return ans;
29 }
30 void init(){
31     for(int i=1;i<=m;i++){
32         for(int l=1,r;l<=n;l=r+1){
33             r=l;
34             if(a[l][i]==0)continue;
35             while (a[r+1][i]==1)r++;
36             for(int j=l;j<=r;j++)cpp[j][i]=r-j+1;
37         }
38     }
39 }
40 int main(){
41     while (scanf("%d%d",&n,&m)!=EOF) {
42         memset(a,0, sizeof(a));
43         memset(cpp,0, sizeof(cpp));
44         for (int i = 1; i <= n; i++)for (int j = 1; j <= m; j++)scanf("%d", &a[i][j]);
45         init();
46         int ans = 0;
47         for (int i = 1; i <= n; i++)
48             ans = max(ans, slove(cpp[i]));
49         printf("%d\\n", ans);
50     }
51 }
View Code

 hdu 5033

坐标轴上竖n个竿子,问你在(?,0)这个点向左向右能看到的角度范围。

单调栈处理出来每个位置向左向右能看到的竿子。

对于Xa<Xb<Xc这样的竿子来说,如果a能挡住b,那么a肯定能挡住c,所以pop(b)

询问输出是换行的。。。我一开始输出的空格给我wrong answer...坑死我了,理论1A

不memset 点的话答案会不对,,不知道为什么。

技术图片
 1 #include <bits/stdc++.h>
 2 #define pb(x) push_back(x)
 3 using namespace std;
 4 typedef double db;
 5 const db pi=acos(-1);
 6 const int N = 2e5+5;
 7 struct point {
 8     db x,y;
 9     bool operator <(const point &k1)const {return x<k1.x;}
10     int id;
11 };
12 point p[N];int que[N],lef[N],rig[N];db ans[N];
13 int T,n,cas,q,x;
14 int main(){
15     scanf("%d",&T);
16     while (cas++<T){
17 //        memset(ans,0, sizeof(ans));
18 //        memset(que,0, sizeof(que));
19 //        memset(lef,0, sizeof(lef));
20 //        memset(rig,0, sizeof(rig));
21         memset(p,0, sizeof(p));
22         scanf("%d",&n);
23        for(int i=1;i<=n;i++){
24            scanf("%lf%lf",&p[i].x,&p[i].y);
25        }
26        scanf("%d",&q);
27        for(int i=1;i<=q;i++){
28            scanf("%lf",&p[i+n].x);
29            p[i+n].y=0;p[i+n].id=i;
30        }
31        sort(p+1,p+1+n+q);
32        int r=0;
33        for(int i=1;i<=n+q;i++){
34            while (r>0&&p[que[r]].y<=p[i].y){
35                r--;
36            }
37            while (r>1&&(p[que[r]].y-p[i].y)/(-p[que[r]].x+p[i].x)<=(p[que[r-1]].y-p[i].y)/(-p[que[r-1]].x+p[i].x)){
38                r--;
39            }
40            lef[i] = que[r];
41            que[++r] = i;
42        }
43        r=0;
44        for(int i=n+q;i>=1;i--){
45            while (r>0&&p[que[r]].y<=p[i].y){
46                r--;
47            }
48            while (r>1&&(p[que[r]].y-p[i].y)/(p[que[r]].x-p[i].x)<=(p[que[r-1]].y-p[i].y)/(p[que[r-1]].x-p[i].x)){
49                r--;
50            }
51            rig[i] = que[r];
52            que[++r] = i;
53        }
54        for(int i=1;i<=n+q;i++){
55             if(r=p[i].id){
56                 ans[r] = atan((-p[lef[i]].x+p[i].x)/(p[lef[i]].y-p[i].y))+atan((p[rig[i]].x-p[i].x)/(p[rig[i]].y-p[i].y));
57                 ans[r] = ans[r]*180/pi;
58             }
59        }
60        printf("Case #%d\\n",cas);
61        for(int i=1;i<=q;i++){
62            printf("%.11f\\n",ans[i]);
63        }
64     }
65 }
66 /**
67 3
68 3
69 1 2
70 2 1
71 5 1
72 1
73 4
74  */
View Code

 

以上是关于单调栈&单调队列入门的主要内容,如果未能解决你的问题,请参考以下文章

单调栈&单调队列

单调队列/单调栈入门详解+题目推荐

数据结构——单调栈&单调队列(解决滑动窗口问题)

单调栈 & 单调队列

单调队列&单调栈归纳

7.14 单调栈 单调队列 +dp优化