4444: [Scoi2015]国旗计划

Description

A国正在开展一项伟大的计划——国旗计划。这项计划的内容是边防战士手举国旗环绕边境线奔袭一圈。这
项计划需要多名边防战士以接力的形式共同完成,为此,国土安全局已经挑选了N名优秀的边防战上作为这
项计划的候选人。
A国幅员辽阔,边境线上设有M个边防站,顺时针编号1至M。每名边防战士常驻两个边防站,并且善于
在这两个边防站之间长途奔袭,我们称这两个边防站之间的路程是这个边防战士的奔袭区间。n名边防战士
都是精心挑选的,身体素质极佳,所以每名边防战士的奔袭区间都不会被其他边防战士的奔袭区间所包含。
现在,国十安全局局长希望知道,至少需要多少名边防战士,才能使得他们的奔袭区间覆盖全部的边境线,
从而顺利地完成国旗计划。不仅如此,安全局局长还希望知道更详细的信息:对于每一名边防战士,在他必
须参加国旗计划的前提下,至少需要多少名边防战士才能覆盖全部边境线,从而顺利地完成国旗计划。

Input

第1行,包含2个正整数N,M,分别表示边防战士数量和边防站数量。
随后n行,每行包含2个正整数。其中第i行包含的两个正整数Ci、Di分别表示i号边防战士常驻的两个边防站编号,
Ci号边防站沿顺时针方向至Di号边防站力他的奔袭区间。数据保证整个边境线都是可被覆盖的。
题解:
乱搞竟然跑的飞快。
发现好像时间复杂度是O(n)
首先把环搞成链。
然后按l排个序,暴力找每个点下一个点,然后建一条边,
然后发现变成了一个以2*n为根的树,记录每个点的深度
对没错,就是dfs,然后跟新一下答案。
#include<cstdio>
#include<cstdlib>
#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;
const int N=400010;
struct node{
	int l,r,id;
}sa[N*2];
int n,m;
bool cmp(node x,node y)
{
	return x.l<y.l;
}
struct node1{
	int x,y,next;
}ss[N*2];int len=0,first[N];
void ins(int x,int y)
{
	len++;
	ss[len].x=x;
	ss[len].y=y;
	ss[len].next=first[x];
	first[x]=len;
}
int ans[N],sta[N],tot=0,dep[N];
void dfs(int x,int k)
{
	sta[++tot]=x;
	if(sa[x].id!=-1)
	{
		while(k<tot&&sa[sta[k+1]].r>=sa[x].l+m) k++;
		//printf("%d %d\n",sta[k],x);
		ans[sa[x].id]=dep[x]-dep[sta[k]]+1;
	}
	for(int i=first[x];i!=-1;i=ss[i].next)
	{
		int y=ss[i].y;
		dep[y]=dep[x]+1;
		dfs(y,k);
	}
	tot--;
}
int main()
{
	scanf("%d%d",&n,&m);
	int l1,r1;
	for(int i=1;i<=n;i++)
	{
		scanf("%d%d",&l1,&r1);
		if(l1>r1) r1+=m;
		sa[i].l=l1;sa[i].r=r1;sa[i].id=i;
		sa[i+n].l=l1+m;sa[i+n].r=r1+m;sa[i+n].id=-1;
	}
	sort(sa+1,sa+1+n*2,cmp);
	memset(first,-1,sizeof(first));
	n*=2;int yu=1;
	for(int i=1;i<n;i++)
	{
		while(yu<n&&sa[i].r>=sa[yu+1].l) yu++;//printf("!%d %d\n",yu,i);
		ins(yu,i);
	}
	n>>=1;dep[n*2]=1;
	dfs(n*2,1);
	for(int i=1;i<=n;i++)
	printf("%d ",ans[i]);
}



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值