SCOI2015 国旗计划

版权声明: https://blog.csdn.net/DancingZ/article/details/82813011

Description

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

Input

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

Output

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

Sample Input

4 8 2 5 4 7 6 1 7 3

Sample Output

3 3 4 3

Hint

【样例说明】
  若1号边防战士必须参加,1、2、4号边防战士可覆盖整个边境线,因此至少需要3名边防战士完成国旗计划;同理,若2号边防战士或4号边防战士必须参加,也需要3名边防战士完成国旗计划;若3号边防战士必须参加,则需要1、2、3、4号边防战士才能完成国旗计划,因此至少需要4名边防战士。
【数据范围】
  对于40%的数据,n<=2000,m<=5000
  另有30%的数据,保证所有答案不超过100
  对于100%的数据,n<=200000,m<=10^9,1<=Ci,Di<=m

上一道训练场的加强版,将环拉成链扩大一倍。然后就和训练场做法一样。

#include<bits/stdc++.h>
using namespace std;
const int Maxn=400005;
#define ll long long
struct Soldier{
	ll l,r;int idx;
	bool operator <(const Soldier&S) const {
		return l<S.l;
	}
}s[Maxn];
int n,m,ans[Maxn];
int f[Maxn][20];
void ST(){
	s[0]=(Soldier){0,1ll<<60};
	s[n+1]=(Soldier){s[n].r,1ll<<60};
	for(int i=1,j=1;i<=n;++i){
		while(j<=n&&s[i].r>=s[j+1].l)++j;
		f[i][0]=j;
	}
	int maxlog=log2(n);
	for(int j=1;j<=maxlog;++j)
		for(int i=1;i<=n;++i)
			f[i][j]=f[f[i][j-1]][j-1];
}
int main(){
	scanf("%d%d",&n,&m);
	for(int i=1;i<=n;++i){
		ll l,r;scanf("%lld%lld",&l,&r);
		if(r<l)r+=m;
		s[i]=(Soldier){l,r,i};
		s[n+i]=(Soldier){l+m,r+m,i};
	}
	n<<=1;sort(s+1,s+n+1);
	ST();
	for(int i=1;i<=n;++i){
		int ret=1,maxlog=log2(n);
		int x=i,t=m-(s[i].r-s[i].l);
		for(int j=maxlog;j>=0;--j)if(f[x][j]!=0&&f[x][j]!=n+1&&t-(s[f[x][j]].r-s[x].r)>=0){
			t-=(s[f[x][j]].r-s[x].r);
			x=f[x][j];
			ret+=1<<j;
		}
		if(t>0)for(int j=0;j<=maxlog;++j)
			if(f[x][j]!=0&&f[x][j]!=n+1&&t-(s[f[x][j]].r-s[x].r)<=0){
				t-=(s[f[x][j]].r-s[x].r);
				ret+=1<<j;
				break;
			}
		if(t<=0)ans[s[i].idx]=ret;
	}
	for(int i=1;i<=n/2;++i)cout<<ans[i]<<" ";
	return 0;
}

猜你喜欢

转载自blog.csdn.net/DancingZ/article/details/82813011