这题太巧妙了。
题意是,给定2*10^5个区间。然后2*10^5组询问,每次询问一个区间,问至少需要几个给定区间,才能将其完全覆盖。坐标范围5*10^5。
如果只有一个询问区间,是经典的贪心问题。我们每次选择,尽可能覆盖的靠右的区间。
但是这题显然贪心的话,时间是不够的。
考虑使用倍增进行预处理。
我们用dp[i][o]表示从i点开始,选择o个区间,能覆盖到最远哪个点。为-1,则表示不存在。
那么显然如果dp[i][o - 1] != -1 时,dp[i][o] = dp[dp[i][o - 1]][o - 1]。否则为-1。
那么我么如何求出dp[i][0]呢?读入的时候,dp[tx][0] = max(dp[tx][0],ty)。然后从1到5*10^5,满足dp[i - 1][0]包括i点的条件下,递推下即可,dp[i][0] = max(dp[i][0],dp[i - 1][0])。
考虑查询询问。
类似倍增LCA,我们从大到小,试着跳,跳到或跳过,就不跳,以此避免跳多浪费。最后一定跟右端点只差一步,答案+1,即可。
1 #include <cstdio> 2 #include <cmath> 3 #include <algorithm> 4 #include <cstring> 5 using namespace std; 6 int ans,n,m; 7 int dp[500010][20]; 8 int main() 9 { 10 memset(dp,-1,sizeof(dp)); 11 scanf("%d%d",&n,&m); 12 int tl,tr; 13 for (int i = 1;i <= n;i++) 14 { 15 scanf("%d%d",&tl,&tr); 16 dp[tl][0] = max(dp[tl][0],tr); 17 } 18 for (int i = 1;i <= 500000;i++) 19 if (dp[i - 1][0] >= i && dp[i - 1][0] > dp[i][0]) 20 dp[i][0] = dp[i - 1][0]; 21 int t = log2(500000); 22 for (int o = 1;o <= t;o++) 23 { 24 for (int i = 0;i <= 500000;i++) 25 { 26 if (dp[i][o - 1] == -1) 27 continue; 28 dp[i][o] = dp[dp[i][o - 1]][o - 1]; 29 } 30 } 31 for (;m;m--) 32 { 33 ans = 0; 34 scanf("%d%d",&tl,&tr); 35 for (int o = t;o >= 0;o--) 36 { 37 if (dp[tl][o] < tr && dp[tl][o] != -1) 38 { 39 ans += (1 << o); 40 tl = dp[tl][o]; 41 } 42 } 43 if (dp[tl][0] >= tr) 44 printf("%d\n",ans + 1); 45 else 46 printf("-1\n"); 47 } 48 return 0; 49 }
原文地址:https://www.cnblogs.com/iat14/p/11620211.html
时间: 2024-11-02 01:41:25