Address
Solution
先解决一个小问题:如何判断一个连续子段是否合法。
很容易得出,
a
[
x
…
y
]
a[x\dots y]
a[x…y] 合法当且仅当对于每个
i
∈
[
x
,
y
]
i\in[x,y]
i∈[x,y] 都有
min
r
[
i
…
y
]
≥
l
i
\min r[i\dots y]\ge l_i
minr[i…y]≥li 。
我们从左到右枚举
y
y
y ,需要维护出这时候满足条件的最小的
x
x
x 。
显然
x
x
x 随
y
y
y 单调不减。初始时
x
x
x 为
1
1
1 。
这样我们就能用尺取法计算答案了。
用一个单调队列,维护
min
r
[
i
…
y
]
\min r[i\dots y]
minr[i…y] 相同的段。
也就是说单调队列中每个位置是一个区间
[
a
,
b
]
[a,b]
[a,b] ,满足
min
r
[
a
…
y
]
\min r[a\dots y]
minr[a…y] 、
min
r
[
a
+
1
…
y
]
\min r[a+1\dots y]
minr[a+1…y] 、
…
\dots
… 、
min
r
[
b
…
y
]
\min r[b\dots y]
minr[b…y] 相同。同时每个位置需要维护
min
r
[
a
…
y
]
\min r[a\dots y]
minr[a…y] 以及
max
l
[
a
…
b
]
\max l[a\dots b]
maxl[a…b] 。
当
y
+
1
y+1
y+1 插入队列时,
就将队尾所有满足
min
r
[
a
…
y
]
≥
a
y
+
1
\min r[a\dots y]\ge a_{y+1}
minr[a…y]≥ay+1 的区间全部踢出队列,设踢出的最后一个区间是
[
u
,
v
]
[u,v]
[u,v] 。
然后把区间
[
u
,
y
+
1
]
[u,y+1]
[u,y+1] 插入队尾并维护
min
r
[
u
…
y
+
1
]
\min r[u\dots y+1]
minr[u…y+1] 及
max
l
[
u
…
y
+
1
]
\max l[u\dots y+1]
maxl[u…y+1] 。
如果这时候出现
min
r
[
u
…
y
+
1
]
\min r[u\dots y+1]
minr[u…y+1] (即
a
y
+
1
a_{y+1}
ay+1 )
<
max
l
[
u
…
y
+
1
]
<\max l[u\dots y+1]
<maxl[u…y+1] 的情况,那么这种情况是不合法的。
这时候不停地从队首出队(
x
x
x 加一),直到
a
y
+
1
≥
max
l
[
x
…
y
+
1
]
a_{y+1}\ge\max l[x\dots y+1]
ay+1≥maxl[x…y+1] 为止。
我们还需要另一个单调队列维护
max
l
[
x
…
y
+
1
]
\max l[x\dots y+1]
maxl[x…y+1] 的值。
时间复杂度
O
(
n
)
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;
}