标签:ext scan its 维护 端点 == bool pac +=
题意简述:
有 \(m\) 个区间,每一段区间为 \([L_i,R_i]\),现在有一个长度为 \(n\) 的线段,问最少选择多少个区间,才能够覆盖整个线段。
\(\texttt{Data Range: }1\leq m \leq 2.5\times 10^4,\ 1\leq n \leq 10^6\)。
设 \(dp_i\) 表示只选择 \(i\) 左边的区间,覆盖区间 \([1,i]\) 最少选择多少个区间。
假设当前区间左端点为 \(l\),右端点为 \(r\),那么状态的转移就是 \(dp_r = \min\limits_{l-1\leq j < r}\{dp_j\} + 1\)。
然后可以使用一个单点修改、区间查询的线段树维护 \(dp\) 值。
#include <cstdio>
#include <algorithm>
#include <cstring>
using namespace std;
const int N = 25003, M = 1000003, INF = 0x3f3f3f3f;
int n, m;
struct Node
{
int l, r;
} a[N];
int tr[M << 2];
int f[M];
inline bool cmp(Node x, Node y)
{
if (x.r != y.r) return x.r < y.r;
return x.l < y.l;
}
inline int ls(int p) {return p << 1;}
inline int rs(int p) {return p << 1 | 1;}
inline void pushup(int p) {tr[p] = min(tr[ls(p)], tr[rs(p)]);}
void build(int l, int r, int p)
{
tr[p] = INF;
if (l == r) return;
int mid = (l + r) >> 1;
build(l, mid, ls(p)); build(mid + 1, r, rs(p));
}
void modify(int k, int v, int l, int r, int p)
{
if (l == r) {tr[p] = min(tr[p], v); return;}
int mid = (l + r) >> 1;
if (k <= mid) modify(k, v, l, mid, ls(p));
else modify(k, v, mid + 1, r, rs(p));
pushup(p);
}
int getans(int ql, int qr, int l, int r, int p)
{
if (ql <= l && r <= qr) return tr[p];
int mid = (l + r) >> 1;
int res = INF;
if (ql <= mid) res = getans(ql, qr, l, mid, ls(p));
if (qr > mid) res = min(res, getans(ql, qr, mid + 1, r, rs(p)));
return res;
}
int main()
{
scanf("%d%d", &m, &n);
for (int i = 1; i <= m; i+=1) scanf("%d%d", &a[i].l, &a[i].r);
build(0, n, 1);
sort(a + 1, a + 1 + m, cmp);
memset(f, 0x3f, sizeof f);
f[0] = 0;
modify(0, 0, 0, n, 1);
for (int i = 1; i <= m; i+=1)
{
f[a[i].r] = min(f[a[i].r], getans(a[i].l - 1, a[i].r - 1, 0, n, 1) + 1);
modify(a[i].r, f[a[i].r], 0, n, 1);
}
if (f[n] == INF) f[n] = -1;
printf("%d\n", f[n]);
return 0;
}
标签:ext scan its 维护 端点 == bool pac +=
原文地址:https://www.cnblogs.com/xsl19/p/12772302.html