测量温度 [单调队列] 思维题

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/CQBZLYTina/article/details/85884424

Description

某国进行了连续N(1<=N<=1000000)天的温度测量,测量存在误差,测量结果是第i天温度在[l_i,r_i]范围内。其中-10 ^ 9<l_i<=r_i<=10 ^ 9
求最长的连续的一段,满足该段内可能温度不降。

Input

第一行一个整数n。

接下来n行,每一行两个整数,表示l_i和r_i。

Output

接下来输出一个整数,表示答案。

Sample Input

6
6 10
1 5
4 8
2 5
6 8
3 5

Sample Output

4

分析

考试的时候没有考虑周到 想的是只要后面那一天有值大于等于前一天即可 也就是前后两天的温度区间第二天的右端点大于等于前一天的左端点即可

看起来没有毛病昂 只要把满足这样条件的天数连在一起就可以了

然而

我还是 too naive

可能会有这样的情况

他们是前后两天两两满足这个条件的 可是第三天却比第一天小

所以:
当前这一天的上限大于等于前面 任意一天的下限

基于此,我们要记录前面温度的下限的最大值,并每次都和当前温度上限进行比较 如果大于 由于要连续 则之前记录的最大值作废
要在后面重新找一个值来作为满足当前这一天的不降区间的起点

如果for一次去找这个当前不降区间的左端点 复杂度会爆掉
那么为了快速找到,我们可以维护一个下限单调递减的单调队列

每一次弹出队头后取值却不能取当前队头元素
队头元素前面可能还有属于当前不降区间的天数。
正确的左端点应该是上一个队头元素(它刚刚被弹出队列)的后一天
后一天不一定会在队列中 而如果后一天不满足当前下限的话 它也一定不会满足上一个下限 那么上一次他就已经有过操作

代码

#include<cstdio>
#include<deque>
using namespace std;
#define MAXN 1000005
int ans,n;
struct node{
	int l,r;
}a[MAXN];
deque<int>Q;
int main()
{
	scanf("%d",&n);
	for(int i=1;i<=n;i++)
		scanf("%d %d",&a[i].l,&a[i].r);
	ans=1;
	Q.push_back(1);
	int j,tmp=0/*队头一次都没有弹出的时候*/;
	for(int i=2;i<=n;i++)
	{
		while(!Q.empty())
		{
			j=Q.front();
			if(a[i].r<a[j].l)
			{
				Q.pop_front();
				tmp=j;
			}
			else break;
		}
		ans=max(ans,i-tmp);
		while(!Q.empty())
		{
			j=Q.back();
			if(a[i].l>=a[j].l)
				Q.pop_back();//这里之前错写成了front() QAQ 
			else break;
		}
		Q.push_back(i);
	}
	printf("%d\n",ans);
	return 0;
} 

猜你喜欢

转载自blog.csdn.net/CQBZLYTina/article/details/85884424