codeforce 1175E Minimal Segment Cover ST表 倍增思想

这题太巧妙了。

题意是,给定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 }

 

posted @ 2019-10-03 17:27  IAT14  阅读(207)  评论(0编辑  收藏  举报