版权声明:本文为hzy原创文章,未经博主允许不可随意转载。 https://blog.csdn.net/Binary_Heap/article/details/82822497
题解
看起来是差分约束,但是USACO出题人又卡SPFA了!
这里有一种巧妙的DP方法。
: 必须放,最多能放多少个.
考虑上一个可以放在哪里。
: 完全在
左边的区间,左端点的最大值 (不能不放)
: 包含
的区间中,左端点的最小值
(只能放
个)
这个怎么求呢?
给一个区间
,用
去更新
,用
去更新
。最后
取前缀最大值,
取后缀最小值。
(这个具体原因可以根据
的定义思考一下)
于是:
考虑到
数组满足单调性,可以使用单调队列优化(线段树优化应该也行)
#include <cstdio>
#include <ios>
using std :: max;
using std :: min;
const int N = 200010;
int n, m, ans;
int l[N], r[N], f[N];
//l(i):完全在i左边的区间,左端点的最大值 (不能不放)
//r(i):包含i的区间中,左端点的最小值-1 (只能放1个)
int main() {
scanf("%d%d", &n, &m);
for(int i = 1; i <= n + 1; i ++) r[i] = i - 1; //一个位置只能有一个点
for(int i = 1, x, y; i <= m; i ++) {
scanf("%d%d", &x, &y);
r[y] = min(r[y], x - 1);
l[y + 1] = max(l[y + 1], x);
}
for(int i = n; i; i --) r[i] = min(r[i], r[i + 1]);
for(int i = 1; i <= n; i ++) l[i] = max(l[i], l[i - 1]);
static int hd = 0, bk = 1, q[N] = {0}, j = 1;
for(int i = 1; i <= n + 1; i ++) {
for(; j <= n && j <= r[i]; ++ j)
if(~ f[j]) {
for(; hd < bk && f[j] > f[q[bk - 1]]; -- bk) ;
q[bk ++] = j;
}
for(; hd < bk && q[hd] < l[i]; ++ hd) ;
f[i] = hd < bk ? f[q[hd]] + 1 : -1;
if(~ f[i]) ans = max(ans, f[i]);
}
printf("%d\n", (~ f[n + 1]) ? f[n + 1] - 1 : -1);
return 0;
}