1. 程式人生 > >[BZOJ2276][Poi2011]Temperature(單調佇列)

[BZOJ2276][Poi2011]Temperature(單調佇列)

Address

洛谷P3522
BZOJ2276
LOJ#2164

Solution

先解決一個小問題:如何判斷一個連續子段是否合法。
很容易得出, a [ x y ] a[x\dots y]

合法當且僅當對於每個 i [ x , y ] i\in[x,y]
都有 min r [ i y ]
l i \min r[i\dots y]\ge l_i

我們從左到右列舉 y y ,需要維護出這時候滿足條件的最小的 x x
顯然 x x y y 單調不減。初始時 x x 1 1
這樣我們就能用尺取法計算答案了。
用一個單調佇列,維護 min r [ i y ] \min r[i\dots y] 相同的段。
也就是說單調佇列中每個位置是一個區間 [ a , b ] [a,b] ,滿足 min r [ a y ] \min r[a\dots y] min r [ a + 1 y ] \min r[a+1\dots y] \dots min r [ b y ] \min r[b\dots y] 相同。同時每個位置需要維護 min r [ a y ] \min r[a\dots y] 以及 max l [ a b ] \max l[a\dots b]
y + 1 y+1 插入佇列時,
就將隊尾所有滿足 min r [ a y ] a y + 1 \min r[a\dots y]\ge a_{y+1} 的區間全部踢出佇列,設踢出的最後一個區間是 [ u , v ] [u,v]
然後把區間 [ u , y + 1 ] [u,y+1] 插入隊尾並維護 min r [ u y + 1 ] \min r[u\dots y+1] max l [ u y + 1 ] \max l[u\dots y+1]
如果這時候出現 min r [ u y + 1 ] \min r[u\dots y+1] (即 a y + 1 a_{y+1} < max l [ u y + 1 ] <\max l[u\dots y+1] 的情況,那麼這種情況是不合法的。
這時候不停地從隊首出隊( x x 加一),直到 a y + 1 max l [ x y + 1 ] a_{y+1}\ge\max l[x\dots y+1] 為止。
我們還需要另一個單調佇列維護 max l [ x y + 1 ] \max l[x\dots y+1] 的值。
時間複雜度 O ( n ) O(n) 非常優秀。

Code

#include <cmath>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define For(i, a, b) for (i = a; i <= b; i++)

inline int read()
{
	int res = 0; bool bo = 0; char c;
	while (((c = getchar()) < '0' || c > '9') && c != '-');
	if (c == '-') bo = 1; else res = c - 48;
	while ((c = getchar()) >= '0' && c <= '9')
		res = (res << 3) + (res << 1) + (c - 48);
	return bo ? ~res + 1 : res;
}

template <class T>
T Max(T a, T b) {return a > b ? a : b;}

const int N = 1e6 + 5;

int n, l[N], r[N], H1, T1, Q2[N], H2, T2, ans,
L[N], R[N], maxl[N], maxr[N];

int main()
{
	int i;
	n = read();
	For (i, 1, n) l[i] = read(), r[i] = read();
	For (i, 1, n)
	{
		int lst = i, mxl = l[i];
		while (H1 < T1 && maxr[T1] >= r[i])
			lst = L[T1], mxl = Max(mxl, maxl[T1--]);
		L[++T1] = lst; R[T1] = i;
		maxl[T1] = mxl; maxr[T1] = r[i];
		while (H2 < T2 && l[Q2[T2]] < l[i]) T2--;
		Q2[++T2] = i;
		if (maxr[T1] < maxl[T1])
		{
			H1 = T1 - 1;
			while (H2 < T2 && maxr[T1] < l[Q2[H2 + 1]])
				lst = Q2[++H2];
			L[T1] = lst + 1;
			maxl[T1] = l[Q2[H2 + 1]];
		}
		ans = Max(ans, R[T1] - L[H1 + 1] + 1);
	}
	std::cout << ans << std::endl;
	return 0;
}