题意:给你n个区间和m次询问,每次询问一个区间[l, r]至少需要几个区间覆盖?
思路:如果只有一个区间,并且区间是整个取值范围的话,这是一个经典的区间覆盖问题,我们都知道贪心可以解决。现在我们需要快速知道对于一个指定区间至少需要多少个区间来覆盖。我们有一个初步想法,我们可以预处理出包含某一个点的区间中最大的右端点,这样就可以贪心的解决一个区间的问题了。但是,这种做法肯定可以被卡掉,所以我们用倍增来优化这个过程,设st[i][j]是从i位置走连续的2 ^ j个区间可以到的最右端的位置,正常的倍增处理即可。需要注意,如果左半边的区间已经不连续了,则置成-1。然后用试填法。有一个剪枝,我们读入一个区间,先判断左端点走最大的步数(2 ^ (mx - 1))可不可以到右端点,如果到不了,说明就无法覆盖,直接输出-1。
代码:
#include <bits/stdc++.h> using namespace std; const int maxn = 500010; int st[maxn][20]; int main() { int n, m, x, y, mx = 0; memset(st, -1, sizeof(st)); scanf("%d%d", &n, &m); for (int i = 1; i <= n; i++) { scanf("%d%d", &x, &y); st[x][0] = max(st[x][0], y); } for (int i = 1; i <= 5e5; i++) { if(st[i - 1][0] >= i && st[i - 1][0] > st[i][0]) st[i][0] = st[i - 1][0]; } for (mx = 1; (1 << mx) <= 5e5; mx++) for (int j = 0; j <= 5e5; j++) { if(st[j][mx - 1] == -1) st[j][mx] = -1; else st[j][mx] = st[st[j][mx - 1]][mx - 1]; } while(m--) { scanf("%d%d", &x, &y); int ans = 0; if(st[x][mx - 1] < y) { printf("-1 "); continue; } for (int j = mx - 1; j >= 0; j--) { if(st[x][j] < y && st[x][j] > x) { ans |= (1 << j); x = st[x][j]; } } printf("%d ", ans + 1); } }