CodeForces-1175E Minimal Segment Cover
题目描述
现有\(n\)条线段,每条线段的左右端点为\(L_i,R_i\),保证\(L_i \le R_i\).
有\(m\)个询问,每次查询\(X_i,Y_i\)区间内所有点被覆盖所需的线段的最小值。
Input
输入第一行包含两个整数\(n,m\),含义如上所述。
接下来,有\(n\)行,每行有两个整数。
第\(i+1\)行包含\(2\)个整数,分别表示\(L_i,R_i\) 。
接下来\(m\)行,表示\(m\)个询问。
\(1 \le n,m \le 2e5\)
\(0 \le L_i \le R_i \le 5e5\)
\(0 \le X_i \le Y_i \le 5e5\)
Output
对于每个询问输出一个答案。
若无法覆盖,输出\(-1\)即可。
Sample Input
2 3
1 3
2 4
1 3
1 4
3 4
3 4
1 3
1 3
4 5
1 2
1 3
1 4
1 5
Sample Output
1
2
1
1
1
-1
-1
利用倍增维护线段覆盖到的区间。
首先,我们发现对于一个端点我们只用关心能覆盖它的线段最远能覆盖到哪里。
对于每个左端点处理出用同一条线段最远的右端点。
那么,覆盖的过程就是从左端点跳到最远的点,\(Ans++\),重复执行这个过程直到覆盖到右端点。
如果暴力模拟,每次从一个段点跳到另一个端点,时间复杂度\(O(n)\)。
仔细想想,我们发现这个过程和\(LCA\)的过程很像,于是我们就可以用倍增维护了。
\(Fa[i][j]\) 表示用\(1<<j\)条线段,从\(i\)开始最远能覆盖到的点。
代码如下
#include <cstdio>
#include <cstring>
#include <map>
#include <queue>
#include <iostream>
#include <algorithm>
using namespace std;
#define int long long
#define u64 unsigned long long
#define Raed Read
#define reg register
#define debug(x) cerr<<#x<<" = "<<x<<endl;
#define rep(a,b,c) for(reg int a=(b),a##_end_=(c); a<=a##_end_; ++a)
#define ret(a,b,c) for(reg int a=(b),a##_end_=(c); a<a##_end_; ++a)
#define drep(a,b,c) for(reg int a=(b),a##_end_=(c); a>=a##_end_; --a)
#define erep(i,G,x) for(reg int i=(G).Head[x]; i; i=(G).Nxt[i])
inline int Read() {
int res = 0, f = 1;
char c;
while (c = getchar(), c < 48 || c > 57)if (c == '-')f = 0;
do res = (res << 3) + (res << 1) + (c ^ 48);
while (c = getchar(), c >= 48 && c <= 57);
return f ? res : -res;
}
template<class T>inline bool Min(T &a, T const&b) {
return a > b ? a = b, 1 : 0;
}
template<class T>inline bool Max(T &a, T const&b) {
return a < b ? a = b, 1 : 0;
}
const int N = 2e5 + 5, M = 5e5 + 5, mod = 1e6 + 7;
const int dx[5] = {1, -1, 0, 0, 0}, dy[5] = {0, 0, 0, 1, -1};
const double eps = 1e-6;
int Fa[M][20], R[M];
inline void _main(void) {
int n = Read(), m = Raed();
rep(i, 1, n) {
int x = Raed(), y = Read();
Max(R[x], y);
}
Fa[0][0] = R[0];
rep(i, 1, M - 5)Max(R[i], R[i - 1]), Fa[i][0] = R[i];
rep(j, 1, 19)rep(i, 0, M - 5)Fa[i][j] = Fa[Fa[i][j - 1]][j - 1];
while (m--) {
int Ans = 0, l = Raed(), r = Raed();
drep(i, 19, 0)if (Fa[l][i] < r)l = Fa[l][i], Ans |= 1 << i;
l = Fa[l][0];
if (l < r)Ans = -1;
else Ans++;
printf("%d\n", Ans);
}
}
signed main() {
#define offline1
#ifdef offline
freopen(".in", "r", stdin);
freopen(".out", "w", stdout);
_main();
fclose(stdin); fclose(stdout);
#else
_main();
#endif
return 0;
}