BZOJ2276: [Poi2011]Temperature

题目大意:给定n个区间,你可以为每个区间选定一个这个区间里的数,求最长不下降子串


首先,一段子串[x,y]满足题意,当且仅当这段区间Li的最大值小于等于Ry并且[x,y-1]合法

所以我们根据单调性可以想到一种做法,把I从1到n扫一遍,记录一个指针j,代表以i为起始的最远右端点,然后每次向右扩展的时候用线段树查询一下区间最大值判断可不可行

于是TLE了

然后改成RMQ,虽然还是O(NlogN)但是常数小

然后MLE了

那就只能想O(N)做法了,我们发现他其实只是要求区间最大值,并且两个端点都是单调的,这样我们可以用一个单调队列来解决

具体看代码


#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define N 1000010
using namespace std;
int a[N],b[N];
int q[N],h,t;
int main()
{
	int n,m;
	scanf("%d",&n);
	int i,j,k;
	for(i=1;i<=n;i++)
	scanf("%d%d",&a[i],&b[i]);
	j=1;
	int ans=0;
	a[0]=-1e9-1;b[n+1]=1e9+1;
	q[1]=1;h=t=1;
	for(i=1;i<=n;i++)
	{
		if(j==i) j=i+1;
		if(q[h]==i-1) h++;
		while(j<=n&&a[q[h]]<=b[j])
		{
			while(h<=t&&a[q[t]]<=a[j]) q[t]=0,t--;
			t++;q[t]=j;
			j++;
		}
		ans=max(ans,j-i);
	}
	printf("%d",ans);
}

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值