[bzoj4444] [loj#2007] [洛谷P4155] [Scoi2015] 国旗计划

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

\(n \leq 2\times 10^5\)\(M< 10^9\)\(1 \leq Ci,Di \leq M\)


想法

这道题“整个边境线都可覆盖”以及每名战士的区间不会被包含的性质非常好,所以这道题有很多种做法。

先说我的。
显然的贪心,每个战士 \(i\) 的所选择的下一名战士 \(j\) 一定是起点在 \(i\) 的终点前且 \(j\) 可到达的终点最远
拆环为链,某些战士要放两遍。
由于题目的性质,随便推一下发现如果按起点递增排序,那么终点也是递增的。
于是 \(O(n)\) 就可以知道每个战士的后继战士是谁了。
这连成了一棵树,在树上遍历,对每个战士在从树根到它所在的点二分终点的位置就行了。

\(yy\) 的非常开心~这做法常数也不是很大。

标算似乎是倍增。也是知道每个点的后继结点后往后跳嘛,道理是一样的。


代码

#include<cstdio>
#include<iostream>
#include<algorithm>

using namespace std;

int read(){
	int x=0;
	char ch=getchar();
	while(!isdigit(ch)) ch=getchar();
	while(isdigit(ch)) x=x*10+ch-'0',ch=getchar();
	return x;
}

const int N = 400005;

int n,m;
struct data { int l,r,id; } d[N] ;
bool cmp(data x,data y) { return x.l<y.l; }
int tot,ans[N];

struct node{
	int v;
	node *nxt;
}pool[N],*h[N];
int cnt;
void addedge(int u,int v){ //u->v
	node *p=&pool[++cnt];
	p->v=v; p->nxt=h[u]; h[u]=p;
}
int st[N],top;
void dfs(int u){
	if(d[u].id<=n){
		int l=1,r=top,mid;
		while(l<r){
			mid=(l+r+1)>>1;
			if(st[mid]<d[u].l+m) r=mid-1;
			else l=mid;
		}
		ans[d[u].id]=top-l+2;
	}
	st[++top]=d[u].r;
	for(node *p=h[u];p;p=p->nxt)
		dfs(p->v);
	top--;
}

int main()
{
	n=read(); m=read();
	int l,r;
	for(int i=1;i<=n;i++){
		l=read(); r=read();
		if(l<=r){
			d[++tot]=(data){l,r,i}; 
			d[++tot]=(data){l+m,r+m,i+n}; 
		}
		else d[++tot]=(data){l,r+m,i};
	}
	sort(d+1,d+1+tot,cmp);
	
	r=1;
	for(int i=1;i<tot;i++){
		while(r<tot && d[r+1].l<=d[i].r) r++;
		addedge(r,i);
	}
	dfs(tot);
	for(int i=1;i<n;i++) printf("%d ",ans[i]);
	printf("%d\n",ans[n]);
	
	return 0;
}
posted @ 2019-08-22 22:24  秋千旁的蜂蝶~  阅读(156)  评论(0编辑  收藏  举报