CF1175E Minimal Segment Cover
题意
给出n
个形如[l,r]
的线段
m
次询问,每次询问区间[x,y]
问至少选出几条线段,使得区间[x,y]
的任何一个部位都被至少一条线段覆盖
思路
形如ST
表
dp[x][k]
:从x
开始的点,使用
2
k
2^k
2k条边后,最多覆盖到哪个点的下一个点
预处理
d p [ i ] [ j ] = d p [ d p [ i ] [ j − 1 ] ] [ j − 1 ] dp[i][j]=dp[dp[i][j-1]][j-1] dp[i][j]=dp[dp[i][j−1]][j−1]
对于每个数i
的[0,j]
都要预处理
倍增
从大到小遍历2^j
,如果比v
小则记录边数
for (int i = limit; i >= 0; i--) {
if (dp[u][i] < v)
u = dp[u][i],
ans += (1 << i);
}
代码
const int maxn = 5e5 + 5;
int log[maxn], dp[maxn][31];
void init()
{
log[0] = -1;
for (int i = 1; i < maxn; i++)
log[i] = ((i & (i - 1)) == 0) ? log[i - 1] + 1 : log[i - 1];
for (int i = 1; i < maxn; i++)
dp[i][0] = i;
}
void RMQ()
{
int Lg = log[maxn - 1];
for (int i = 1; i <= Lg; i++)
for (int j = 1; j <= maxn; j++)
dp[j][i] = dp[dp[j][i - 1]][i - 1];
}
int n, m, limit;
int ask(int u, int v)
{
int ans = 0;
for (int i = limit; i >= 0; i--) {
if (dp[u][i] < v)
u = dp[u][i],
ans += (1 << i);
}
if (dp[u][0] >= v)
return ++ans;
else
return -1;
}
int main()
{
init();
scanf("%d%d", &n, &m);
limit = log[n] + 1;
int u, v;
for (int i = 1; i <= n; i++) {
scanf("%d%d", &u, &v);
u++;
v++;
dp[u][0] = max(dp[u][0], v);
}
for (int i = 1; i < maxn; i++)
dp[i][0] = max(dp[i][0], dp[i - 1][0]);
RMQ();
for (int i = 1; i <= m; i++) {
scanf("%d%d", &u, &v);
printf("%d\n", ask(u + 1, v + 1));
}
system("pause");
}