Minimal Segment Cover
前言
最近需要把效率提起来, 注意写题不能太水, 要多自己想
思路
转化题意
给定 \(n\) 个线段,每个线段形如 \([l,r]\)
\(m\) 次询问,每次询问给出 \(x, y\) , 求至少选多少个线段才能使这些线段的并能包含线段 \([x,y]\)
又是这一类线段题, 我们也是做过不少
不用想的太复杂, 我们先考虑一个贪心做法, 对于每一个点, 我们尽可能的往右边选择, 然后再跳到右边的位置之后继续贪心, 这样是 \(\mathcal{O} (nq)\) 的
考虑优化, 容易发现我们可以优化跳的次数, 类似于倍增
代码
#include <bits/stdc++.h>
const int MAXN = 5e5 + 10;
int n, q, f[MAXN][25], k;
int main()
{
scanf("%d %d", &n, &q);
for (int i = 1; i <= n; i++)
{
int l, r;
scanf("%d %d", &l, &r);
f[l][0] = std::max(f[l][0], r);
k = max(k, r);
}
for (int i = 1; i <= k; i++)
f[i][0] = std::max(f[i][0], f[i - 1][0]);
for (int i = 1; i <= 20; i++)
for (int j = 0; j <= k; j++)
f[j][i] = f[f[j][i - 1]][i - 1];
while (q--)
{
int l, r, ans = 0;
scanf("%d %d", &l, &r);
for (int i = 20; i >= 0; i--)
if (f[l][i] < r)
{
ans += 1 << i;
l = f[l][i];
}
printf("%d\n", f[l][0] >= r ? ans + 1 : -1);
}
return 0;
}
总结
倍增优化一类跳跃问题

浙公网安备 33010602011771号