1. 程式人生 > >測量溫度 [單調佇列] 思維題

測量溫度 [單調佇列] 思維題

文章目錄

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; }