[BZOJ2276][Poi2011]Temperature(單調佇列)
阿新 • • 發佈:2018-11-23
Address
Solution
先解決一個小問題:如何判斷一個連續子段是否合法。
很容易得出,
合法當且僅當對於每個
都有
。
我們從左到右列舉
,需要維護出這時候滿足條件的最小的
。
顯然
隨
單調不減。初始時
為
。
這樣我們就能用尺取法計算答案了。
用一個單調佇列,維護
相同的段。
也就是說單調佇列中每個位置是一個區間
,滿足
、
、
、
相同。同時每個位置需要維護
以及
。
當
插入佇列時,
就將隊尾所有滿足
的區間全部踢出佇列,設踢出的最後一個區間是
。
然後把區間
插入隊尾並維護
及
。
如果這時候出現
(即
)
的情況,那麼這種情況是不合法的。
這時候不停地從隊首出隊(
加一),直到
為止。
我們還需要另一個單調佇列維護
的值。
時間複雜度
非常優秀。
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;
}