题目
给出 n n n个形如 [ l , r ] [l,r] [l,r]的线段。 m m m次询问,每次询问区间 [ x , y ] [x,y] [x,y],问至少选出几条线段,使得区间 [ x , y ] [x,y] [x,y]的任何一个部位都被至少一条线段覆盖。
题解
-
首先非常暴力的想法,我们可以把每个点 x x x尽量的往后跳,跳的时候是可以后退的(如下图:
-
这样我们就可以预处理出每个点所能到的最远点
-
然后我们可以把跳的过程用倍增实现,这样就会降低我们的复杂度qwq
c o d e code code
#include <bits/stdc++.h>
using namespace std;
#define maxn 600100
template <typename T>
inline void read(T &s) {
s = 0;
T w = 1, ch = getchar();
while (!isdigit(ch)) { if (ch == '-') w = -1; ch = getchar(); }
while (isdigit(ch)) { s = (s << 1) + (s << 3) + (ch ^ 48); ch = getchar(); }
s *= w;
}
int a[maxn];
int f[maxn][25];
int main() {
int n, m, R = 0;
read(n), read(m);
for (int i = 1; i <= n; ++i) {
int l, r; read(l), read(r);
a[l] = max(a[l], r);
R = max(R, r);
}
for (int i = 1; i <= R; ++i)
a[i] = max(a[i], a[i-1]);
for (int i = 0; i <= R; ++i) f[i][0] = a[i];
for (int j = 1; j <= 20; ++j)
for (int i = 0; i <= R; ++i)
f[i][j] = f[ f[i][j-1] ][j-1];
while (m--) {
int l, r; read(l), read(r);
int ans = 0;
for (int i = 20; i >= 0; --i) {
if (f[l][i] < r)
l = f[l][i], ans += 1<<i;
}
if (a[l] >= r) printf("%d\n", ans+1);
else puts("-1");
}
return 0;
}