[SCOI2015]国旗计划

Posted adelalove

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[SCOI2015]国旗计划相关的知识,希望对你有一定的参考价值。

题目描述

A 国正在开展一项伟大的计划 —— 国旗计划。这项计划的内容是边防战士手举国旗环绕边境线奔袭一圈。这项计划需要多名边防战士以接力的形式共同完成,为此,国土安全局已经挑选了 N 名优秀的边防战上作为这项计划的候选人。

A 国幅员辽阔,边境线上设有 M 个边防站,顺时针编号 1 至 M 。

每名边防战士常驻两个边防站,并且善于在这两个边防站之间长途奔袭,我们称这两个边防站之间的路程是这个边防战士的奔袭区间。

N名边防战士都是精心挑选的,身体素质极佳,所以每名边防战士的奔袭区间都不会被其他边防战士的奔袭区间所包含。

现在,国十安全局局长希望知道,至少需要多少名边防战士,才能使得他们的奔袭区间覆盖全部的边境线,

从而顺利地完成国旗计划。不仅如此,安全局局长还希望知道更详细的信息:对于每一名边防战士,在他必须参加国旗计划的前提下,

至少需要多少名边防战士才能覆盖全部边境线,从而顺利地完成国旗计划。

输入输出格式

输入格式:

 

第一行,包含两个正整数 N,M,分别表示边防战士数量和边防站数量。

随后 N行,每行包含两个正整数。其中第 ii 行包含的两个正整数 CiDi 分别表示 i号边防战士常驻的两个边防站编号,

Ci? 号边防站沿顺时针方向至 Di? 号边防站力他的奔袭区间。数据保证整个边境线都是可被覆盖的。

 

输出格式:

 

输出数据仅 1 行,需要包含 N个正整数。其中,第 j 个正整数表示 j 号边防战士必须参加的前提下至少需要多

少名边防战士才能顺利地完成国旗计划。

 

输入输出样例

输入样例#1: 
4 8
2 5
4 7
6 1
7 3
输出样例#1: 
3 3 4 3

说明

 N?2×10^5,M<10^9,1?Ci?,Di??M 。

 解:

首先破链成环,就转化为了区间覆盖问题。

每一个区间都不能被其他区间所包含,

也就是如果li<lj,那么一定满足ri<rj,然后就可以贪心。 

假设要覆盖整个区间,那么选择的线段是确定的,即每一个战士要找的下一个战士都是确定的。

这样可以按照左端点排序,预处理出每个战士的下一个接力者。

对于必须有这个战士参与,我们可以以这个战士为起点,寻找经过一圈之后再次回来最少需要多少条线段。

因为是链,所以我们用倍增预处理。

f[i][j]表示从i点走2j步到达的点,如果f[i][j]所到达的点没有超出m,就可以从i点走2j步,到达下一个点。 

另外,使用set(stl大法好)可以减少代码量。

技术分享图片
 1 #include<algorithm>
 2 #include<iostream>
 3 #include<cstdio>
 4 #include<cstring>
 5 #include<string>
 6 #include<queue>
 7 #include<cmath>
 8 #include<set>
 9 #define ll long long
10 #define DB double
11 #define mod 1000000007
12 #define eps 1e-3
13 #define inf 147483600
14 using namespace std;
15 inline int read()
16 {
17     int x=0,w=1;char ch=getchar();
18     while(!isdigit(ch)){if(ch==-) w=-1;ch=getchar();}
19     while(isdigit(ch)) x=(x<<3)+(x<<1)+ch-0,ch=getchar();
20     return x*w;
21 }
22 const int N=2e6+10;
23 int n,m,cnt,top;
24 int f[N][30],ans[N];
25 struct yuh{
26   int l,r,id;
27 }c[N];
28 bool cmp(yuh x,yuh y){ return x.l<y.l;}
29 set< pair <int,int> >s;
30 void work(int x)
31 {
32     int id=c[x].id,L=c[x].l+m;
33     for(int i=20;i>=0;--i)
34      if(f[x][i])
35       if(c[f[x][i]].r<L)
36        x=f[x][i],ans[id]+=(1<<i);
37 }
38 int main()
39 {
40     // freopen("flag.in","r",stdin);
41     // freopen("flag.out","w",stdout);
42     n=read();m=read();
43     for(int i=1;i<=n;++i)
44     {
45         int l,r;l=read();r=read();
46         if(l>r) r+=m;
47         cnt++;c[cnt]=(yuh){l,r,i};
48         cnt++;c[cnt]=(yuh){l+m,r+m,0};
49     }
50     sort(c+1,c+cnt+1,cmp);
51     s.insert(make_pair(c[cnt].l,cnt));
52     for(int i=cnt-1;i>=1;--i)
53     {
54         f[i][0]=(--s.upper_bound((make_pair(c[i].r,inf))))->second;
55         s.insert(make_pair(c[i].l,i));
56     }
57     for(int i=1;i<=20;++i)
58      for(int j=cnt;j>=1;--j)
59       f[j][i]=f[f[j][i-1]][i-1];
60     for(int i=1;i<=cnt;++i)
61      if(c[i].id) work(i);
62     for(int i=1;i<=n;++i)
63      printf("%d ",ans[i]+2);
64     return 0;
65 }
View Code

 




以上是关于[SCOI2015]国旗计划的主要内容,如果未能解决你的问题,请参考以下文章

LibreOJ #2007. 「SCOI2015」国旗计划

bzoj4444[Scoi2015]国旗计划

BZOJ4444[Scoi2015]国旗计划 双指针+倍增

[SCOI2015]国旗计划

[luogu] P4155 [SCOI2015]国旗计划(贪心)

BZOJ 4444: [Scoi2015]国旗计划