单调栈+单调队列

单调栈,顾名思义,即单调的栈,栈就不解释了,单调,就是单调增或单调减,也就是说从栈顶向下的元素是递增或递减的。同理,单调队列就是递增或递减的队列。
这两种数据结构当然是拿来用的,他们能被用到什么地方呢,先看一道单调栈的例题(乱头发节)
题目描述
贤正的某 N 头奶牛 (1 <= N <= 80,000) 正在过乱头发节!由于每头牛都 意识到自己凌乱不堪的发型, 宁智贤希望统计出能够看到其他牛的头发的牛的数量。
每一头牛 i有一个高度 h[i] (1 <= h[i] <= 1,000,000,000)而且面向东方排成 一排(在我们的图中是向右)。因此,第i头牛可以看到她前面的那些牛的头, (即i+1, i+2,等等),只要那些牛的高度严格小于她的高度。
例如这个例子:
牛#1 可以看到她们的发型 #2, 3, 4 牛#2 不能看到任何牛的发型 牛#3 可以看到她的发型 #4 牛#4 不能看到任何牛的发型 牛#5 可以看到她的发型 6 牛#6 不能看到任何牛的发型!
让 c[i] 表示第i头牛可以看到发型的牛的数量;请输出 c[1] 至 c[N]的和。 如上面的这个例子,正确解是3 + 0 + 1 + 0 + 1 + 0 = 5。
输入格式
Line 1: 牛的数量 N。
Lines 2…N+1: 第 i+1 是一个整数,表示第i头牛的高度。
输出格式
Line 1: 一个整数表示c[1] 至 c[N]的和。
样例数据
input

6
10
3
7
4
12
2
output
5
数据规模与约定
时间限制:1s1s
空间限制:256MB

先对题目进行分析,每一头牛能看到它前面身高严格低于它的牛,也就是说,我们可以维护一个单调栈(单调递减),当我们要进栈的数大于栈顶时,栈顶的数就对后面的结果没有影响了,所以这时我们就用一个while循环,将前面所有小于我们要插入的数都删除,对答案进行更新,最后所得的就是最终答案。
我们来思考一下,所有的元素至多出一次栈,进一次栈,所以这个算法的时间复杂度是O[n]的。灰常的优秀。
话不多说,上代码。

#include<bits/stdc++.h>
using namespace std;
long long a[100100],b[100100]; 
long long t,n,ans;
int main()
{
	freopen("badhair.in","r",stdin);
	freopen("badhair.out","w",stdout);
	cin>>n;
	for(int i=1;i<=n;i++)
	{
		cin>>a[i];
		while(t!=0&&b[t]<=a[i]) t--;
		b[++t]=a[i];
		ans=ans+t-1;
	}
	cout<<ans<<endl;
	return 0;
}

这个代码里的t是统计我们插入的数之前有多少头牛可以看到它。
这就是单调栈的基本思想。

下面我们说一下单调队列,它的基本思想和单调栈差不多,也是通过维护一个队列,达到让所有元素只进出一次队,达到题目的要求。思想和单调栈大差不差。
这两个数据结构理解起来都不难,就是细节比较多。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值