国旗计划(flag)

国旗计划(flag)

国旗计划(flag)

题目描述

 

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

A国幅员辽阔,边境线上设有m个边防站,顺时针编号1至m。每名边防战士常驻两个边防站,并且善于在这两个边防站之间长途奔袭,我们称这两个边防站之间的路程是这两个边防战士的奔袭区间。N名边防战士都是精心挑选的,身体素质极佳,所以每名边防战士的奔袭区间都不会被其他边防战士的奔袭区间所包含。

现在,国土安全局局长希望知道,至少需要多少名边防战士,才能使得他们的奔袭区间覆盖全部的边境线,从而顺利地完成国旗计划。不仅如此,安全局局长还希望知道更详细的信息:对于每一名边防战士,在他必须参加国旗计划的前提下,至少需要多少名边防战士才能覆盖全部边境线,从而顺利完成国旗计划。

 

 

输入

 

输入数据第1行,包含2个正整数n、m,分别表示边防战士数量和边防站数量。

随后n行,每行包含2个正整数。其中,第i行包含的两个正整数Ci、Di分别表示i号边防战士常驻的两个边防站编号,Ci号边防站沿顺时针方向至Di号边防站为他的奔袭区间。数据保证整个边境线都是可被覆盖的。

 

 

输出

 

输出数据仅1行,需要包含n个正整数。其中,第i个正整数表示i号边防战士必须参加的前提下至少需要多少名边防战士才能顺利地完成国旗计划。

 

 

样例说明

若1号边防战士必须参加,1、2、4号边防战士可覆盖整个边境线,因此至少需要3名边防战士完成国旗计划;同理,若2号边防战士或4号边防战士必须参加,也需要3名边防战士完成国旗计划;若3号边防战士必须参加,则需要1、2、3、4号边防战士才能完成国旗计划,因此至少需要4名边防战士。

数据范围

对于40%的数据,n≤2000,m≤5000。

另有30%的数据,保证所有答案不超过100。

对于100%的数据,n≤2×105,m≤109,1≤Ci,Di≤m。

 


solution

把环复制一边成为链

对于起点i,我要走到i+m

对于每一个战士,可以求出他接的下一个最远走到哪

把这两个战士连边。

那么所有点构成一棵树,我相当于求它的第一个到i+m的祖先

可以发现这是有单调性的,也就是孩子的答案一定比父亲的答案深。

用个队列维护可行的节点即可。

#include<cstdio>
#include<iostream>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#include<cmath>
#define maxn 800005
using namespace std;
int n,m,head[maxn],ans[maxn],tot;
int deep[maxn],R,q[maxn];
struct node{
    int l,r,id;
}s[maxn];
bool cmp(node a,node b){
    return a.l<b.l;
}
struct no{
    int v,nex;
}e[maxn];
void lj(int t1,int t2){
    e[++tot].v=t2;e[tot].nex=head[t1];head[t1]=tot;
}
void dfs(int k,int fa,int T){
    q[++R]=k;deep[k]=deep[fa]+1;
    int now=T;
    if(s[k].id!=0){
        while(s[q[now]].r>=s[k].l+m&&now<=R)now++;
        ans[s[k].id]=deep[k]-deep[q[now-1]]+1;
    }       
    for(int i=head[k];i;i=e[i].nex){
        dfs(e[i].v,k,now);
    }
    R--;
}
int main()
{
    cin>>n>>m;
    for(int i=1;i<=n;i++){
        scanf("%d%d",&s[i].l,&s[i].r);
        s[i].id=i;
        if(s[i].l>s[i].r)s[i].r+=m;
        s[i+n].l=s[i].l+m,s[i+n].r=s[i].r+m;
    }
    sort(s+1,s+n*2+1,cmp);
    int j=1;
    for(int i=1;i<n+n;i++){
        for(;s[j].l<=s[i].r&&j<=n+n;j++);
        lj(j-1,i);
    }
    dfs(n+n,0,1);
    printf("%d",ans[1]);for(int i=2;i<=n;i++)printf(" %d",ans[i]);
    return 0;
}
 

 

posted @ 2018-11-30 19:42 liankewei 阅读( ...) 评论( ...) 编辑 收藏
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值