前言
最近需要把效率提起来, 注意写题不能太水, 要多自己想
思路
转化题意
给定 \(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;
}
总结
倍增优化一类跳跃问题