浅谈单调栈 By cellur925
这位dalao的单调栈文章很棒!我写的是他的题单233. http://www.cnblogs.com/COLIN-LIGHTNING/p/8474668.html
一、单调栈的一般写法
for(int i=;i<=n;i++)
{
int x=;
scanf("%d",&x);
while(x>=sta[top]&&top)
top--;
sta[++top]=x;
}
而各种各样繁杂的题目正是在这个基础上维护一些其他的信息。
二、注意事项
栈不能为空。要随时注意,否则RE。
计数类可能会用到$longlong$。
三、例题详解
例题0 LIS(最长上升子序列)辣个$nlogn$的算法其实本质上就是单调栈...
例题1 音乐会的等待
N个人正在排队进入一个音乐会。人们等得很无聊,于是他们开始转来转去,想在队伍里寻找自己的熟人。队列中任意两个人A和B,如果他们是相邻或他们之间没有人比A或B高,那么他们是可以互相看得见的。
写一个程序计算出有多少对人可以互相看见。(注意,是互相看见)
维护一个单调不增的栈。(因为两个之间没有比他们高的人时他们才能互相看见,中间隔等高个人时是可以互相看见的)
(注意!脑子别晕!233,这是栈!不是队列!栈顶是最后加的!)
当新来的人身高小于栈顶,直接进来。答案在栈非空的情况下加1,这算的是栈顶和当前元素这对。(满足相邻的条件)
当新来的人身高大于栈顶,弹栈直到满足小于(或等于)。因为维护的单调递减的栈,而新生还很高,所以自然能看得见。这里每次弹栈都加上那个元素的个数(具体接下来会讲)。满足性质后,再和栈顶比较。
当新来的人身高等于栈顶,弹栈直到小于。我们把和它相等的都弹走,但是要注意记上和它相等的数出现的次数,以便之后使用,因为相等,所以肯定看的见,为接下来记录了信息(解释了第二种情况)。满足性质后,再和栈顶比较。
综上,我们看出每个元素最多入栈出栈一次,复杂度$O(N)$,每次入栈后,都要在栈不为空的情况下,答案++,因为栈顶(最外面的元素)一定能看见新来的元素。
Code
#include<cstdio>
#include<algorithm> using namespace std;
typedef long long ll; int n,top,x,num;
struct node{
int val,num;
}sta[];
ll ans; int main()
{
scanf("%d",&n);
for(int i=;i<=n;i++)
{
scanf("%d",&x);
node p=(node){x,};
while(x>=sta[top].val&&top)
{
ans+=sta[top].num;
if(sta[top].val==x) p.num+=sta[top].num;
//虽然弹走了 记下 以后用得到
top--;
}
if(top) ans++;
sta[++top]=p;
}
printf("%lld",ans);
return ;
}
Byteburg市东边的建筑都是以旧结构形式建造的:建筑互相紧挨着,之间没有空间.它们共同形成了一条长长的,从东向西延伸的建筑物链(建筑物的高度不一).Byteburg市的市长Byteasar,决定将这个建筑物链的一侧用海报覆盖住.并且想用最少的海报数量,海报是矩形的.海报与海报之间不能重叠,但是可以相互挨着(即它们具有公共边),每一个海报都必须贴近墙并且建筑物链的整个一侧必须被覆盖(意思是:海报需要将一侧全部覆盖,并且不能超出建筑物链,即不能盖着没有海报存在的地方)
读完题后,我们很快就会发现,那个宽度的条件其实是没用的,我们只需要考虑高度就行了。设开始我们需要海报的数量等于矩形的数量,我们再一点点减。那么,我们便可以维护一个高度单调递增的栈,在弹栈过程中,若遇到和自己相等的高度,就将答案减去1,因为如图,我们可以横着盖,我们只需要再把高出来的(於出来的)用一张海报即可。
Code
#include<cstdio>
#include<algorithm> using namespace std; int n,ans,top;
int sta[]; int main()
{
scanf("%d",&n);
for(int i=;i<=n;i++)
{
int y=,x=;
scanf("%d%d",&y,&x);
while(top&&x<=sta[top])
{
if(x==sta[top]) ans++;
top--;
}
sta[++top]=x;
}
printf("%d",n-ans);
return ;
}
以上都是一些比较简单的线性问题。接下来我们要看的是那些或者在二维上,或者掺杂入实际的面积,这些更复杂的问题。
例题3 玉蟾宫 哎又要看Freda学姐和rainbowcat虐狗了
其实这题还有悬线法,是求最大子矩阵的一个方法,这里就不再说了==(大坑)
抽象一下本题的模型:有障碍点的情况下的最大子矩形。
虽然这题是二维的了,但是我们还可以分别计算情况。
首先,我们用一个$f[i][j]$表示在$(i,j)$点,前$i$行,第$j$列,以第$i$行结尾,连续的‘F’个数。(最大可延伸距离)
行与行之间的问题就解决了。
然后在同一行,不同列上的问题就可以用单调栈(单调递增栈)来维护了。
单调栈中存储两个信息。此单位高度$height$,和对应可控宽度$wid$(对应可控我觉得说的非常准确)
同理,我们当前的高度(f数组)大于栈顶时,直接把它压入栈。
否则,就一直弹栈。弹栈的时候,我们要记录矩形的信息来更新答案。它的$wid$是所有弹栈元素的$wid$+1.(因为我们继承了之前的信息,这部分 到之后也是可以用的。因为被弹栈的元素高度均大于当前元素,在可控范围内。)
之后更新答案即可。枚举到最后一列后,把栈都搞空。
Code
#include<cstdio>
#include<algorithm> using namespace std; int n,m,ans,top,tmp,neww;
struct node{
int height,wid;
}sta[];
char qwq[],mapp[][],f[][]; void work(int x)
{
top=;tmp=;neww=;
sta[].height=f[x][];
sta[].wid=;
for(int i=;i<=m;i++)
{
tmp=;
while(f[x][i]<=sta[top].height&&top)
{
tmp+=sta[top].wid;
neww=max(neww,tmp*sta[top].height);
top--;
}
sta[++top].height=f[x][i];
sta[top].wid=tmp+;
}
tmp=;
while(top)
{
tmp+=sta[top].wid;
neww=max(neww,tmp*sta[top].height);
top--;
}
ans=max(ans,neww);
} int main()
{
scanf("%d%d",&n,&m);
for(int i=;i<=n;i++)
for(int j=;j<=m;j++)
{
scanf("%s",qwq+),mapp[i][j]=qwq[];
if(mapp[i][j]=='F') f[i][j]=f[i-][j]+;
}
for(int i=;i<=n;i++) work(i);
printf("%d",ans*);
return ;
}
例题4 Largest Rectangle in a Histogram
在一条水平线上给出若干连续矩形,求包含于这些矩形的并集内部最大矩形的面积。
这应该是单调栈的典型题目惹qwq。
我们假设,到现在为止,读入的矩形高度都是递增的,那么如果突然读入了一个比上一个矩形矮的矩形,那么之前高的矩形搞出来就没有用了(於出来了)
打叉的部分就没用了。没用就删去啊,所以我们在做的事情就是维护一个单调递增的矩形序列。与上题相似,弹矩形的时候,我们同样要维护弹出矩形的答案。
其实这和上一题差不多啦qwq。
Code
#include<cstdio>
#include<algorithm>
#include<cstring> using namespace std;
typedef long long ll; int n,top,x,tmp;
ll ans;
struct node{
int height,wid;
}sta[]; int main()
{
while(scanf("%d",&n)!=EOF&&n)
{
for(int i=;i<=n;i++)
{
tmp=;
scanf("%d",&x);
while(x<=sta[top].height&&top)
{
tmp+=sta[top].wid;
ans=max(ans,1ll*tmp*sta[top].height);
top--;
}
sta[++top].height=x;
sta[top].wid=tmp+;
}
tmp=;
while(top)
{
tmp+=sta[top].wid;
ans=max(ans,1ll*tmp*sta[top].height);
top--;
}
printf("%lld\n",ans);
top=;ans=;
memset(sta,,sizeof(sta));
}
return ;
}
这种更新面积(我也不知道怎么总结)的问题,最后一定要记得把栈搞空啊qwq。
单调栈先告一段落,下一次来看单调队列qwq。
浅谈单调栈 By cellur925的更多相关文章
- 浅谈Java中的栈和堆
人们常说堆栈堆栈,堆和栈是内存中两处不一样的地方,什么样的数据存在栈,又是什么样的数据存在堆中? 这里浅谈Java中的栈和堆 首先,将结论写在前面,后面再用例子加以验证. Java的栈中存储以下类型数 ...
- 浅谈PHP数据结构之栈
今天開始进阶自己的PHP,首先一切的编程语言都须要修炼自己的"内功",何为程序猿的"内功",我想大概就是数据结构和算法了吧 .毕竟是灵魂,是普通程序猿到高级程序 ...
- 虚拟化构建二分图(BZOJ2080 题解+浅谈几道双栈排序思想的题)
虚拟化构建二分图 ------BZOJ2080 题解+浅谈几道双栈排序思想的题 本题的题解在最下面↓↓↓ 不得不说,第一次接触类似于双栈排序的这种题,是在BZOJ的五月月赛上. [BZOJ4881][ ...
- 莫队浅谈&题目讲解
莫队浅谈&题目讲解 一.莫队的思想以及莫队的前置知识 莫队是一种离线的算法,他的实现借用了分块的思想.在学习莫队之前,本人建议学习一下分块,并对其有一定的理解. 二.莫队 现给出一道例题:bz ...
- 浅谈 Fragment 生命周期
版权声明:本文为博主原创文章,未经博主允许不得转载. 微博:厉圣杰 源码:AndroidDemo/Fragment 文中如有纰漏,欢迎大家留言指出. Fragment 是在 Android 3.0 中 ...
- 浅谈Java的throw与throws
转载:http://blog.csdn.net/luoweifu/article/details/10721543 我进行了一些加工,不是本人原创但比原博主要更完善~ 浅谈Java异常 以前虽然知道一 ...
- 浅谈Linux中的信号处理机制(二)
首先谢谢 @小尧弟 这位朋友对我昨天夜里写的一篇<浅谈Linux中的信号处理机制(一)>的指正,之前的题目我用的“浅析”一词,给人一种要剖析内核的感觉.本人自知功力不够,尚且不能对着Lin ...
- 浅谈struts2之chain
转自:http://blog.csdn.net/randomnet/article/details/8656759 前一段时间,有关chain的机制着实困绕了许久.尽管网上有许多关于chain的解说, ...
- 浅谈JAVA集合框架
浅谈JAVA集合框架 Java提供了数种持有对象的方式,包括语言内置的Array,还有就是utilities中提供的容器类(container classes),又称群集类(collection cl ...
随机推荐
- HDU 5335 Walk Out(多校)
Walk Out Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/65536 K (Java/Others)Total Su ...
- zookeeper 服务端上下线,客户端感知
package pfs.y2017.m11.zookeeper.demo03; import java.util.ArrayList; import java.util.List; import or ...
- 前端编程提高之旅(五)----写给大家看的css书
自实习也有几个月的时间了,以爱奇艺实习为敲门砖.进入了眼下这家公司.假设说当初能进爱奇艺是暂时袭击DIV+CSS的话,眼下在这家公司体验到.不论什么技术都必须悉知原理,这样才干做到庖丁解牛.做一 ...
- ScaleYViewPager
https://github.com/eltld/ScaleYViewPager
- OpenStack源码系列---neutron-server
在看过了nova模块的源码之后,再去看OpenStack其它模块的源码会轻松很多,因为框架也是大同小异的.自四月份开通博客写了几篇文章后,真心觉得写篇技术文章如果要把前前后后牵扯到的其它技术内容都做介 ...
- java 的File文件
文件是计算中一种主要的数据存储形式. 首先介绍一下,绝对路径和相对路径.绝对路径是书写完整路径,相对路径是值书写文件的部分路径. d:\java\hello.java 就是据对路径.包括完整的路径d ...
- VS 预先生成事件命令
宏 说明 $(ConfigurationName) 当前项目配置的名称(例如,“Debug|Any CPU”). $(OutDir) 输出文件目录的路径,相对于项目目录.这解析为“输出目录”属性的值. ...
- hdoj 1875 畅通project再续【最小生成树 kruskal && prim】
畅通project再续 Problem Description 相信大家都听说一个"百岛湖"的地方吧,百岛湖的居民生活在不同的小岛中,当他们想去其它的小岛时都要通过划小船来实现. ...
- IDEA maven dependency自动提示
通过File->setting->maven->repositories,选择本地仓库,点击右上角更新,更新maven仓库索引 在pom.xml编写引入依赖的jar包时,已经下载到本 ...
- SpringBoot快速HelloWorld入门
1.新建maven项目 2.pom.xml 里添加SpringBoot所依赖的jar包 <parent> <groupId>org.springframework.boot&l ...