Description

给一个环 \(n\) 个区间,求最小用几个区间覆盖环。

\(1\leqslant n\leqslant 10^6\)

Solution

对每个区间求能接上的扩展的最右距离的区间,然后对每个区间作为第一个区间倍增直到完全覆盖。

Code

#include<bits/stdc++.h>
using namespace std;
int len,n;
#define MAXN 1000010
int fa[MAXN][21];
struct node{int l,r,id;}s[MAXN << 1],u[MAXN << 1];
int tot = 0;
bool cmp_l(node a,node b){return a.l < b.l;}
int main()
{
	scanf("%d%d",&len,&n);
	for(int i = 1;i <= n;++i)scanf("%d%d",&s[i].l,&s[i].r);
	for(int i = 1;i <= n;++i)if((s[i].r + 1) % len == s[i].l % len){puts("1");return 0;}
	for(int i = 1;i <= n;++i)if(s[i].r < s[i].l)s[i].r += len;
	sort(s + 1,s + 1 + n,cmp_l);
	for(int i = 1;i <= n;++i)
	{
		if(i == 1)u[++tot] = s[i];
		else
		{
			if(s[i].r <= u[tot].r)continue;
			else u[++tot] = s[i];
		}
	}
	n = tot;
	for(int i = 1;i <= n;++i)s[i] = u[i];
	for(int i = 1;i <= n;++i)
	{
		s[i + n].l = s[i].l + len;
		s[i + n].r = s[i].r + len;
	}
	for(int i = 1;i <= n * 2;++i)s[i].id = i;
	//for(int i = 1;i <= 2 * n;++i)cout << s[i].l << " " << s[i].r << endl;
	//cout << endl;
	for(int i = 1,j = 1;i <= n;++i)
	{
		while(j < 2 * n && s[j + 1].l <= s[i].r + 1)++j;
		fa[i][0] = s[j].id;
	}
	//for(int i = 1;i <= 2 * n;++i)cout << fa[i][0] << " ";cout << endl;
	for(int i = n + 1;i <= 2 * n;++i)if(fa[i - n][0] <= n)fa[i][0] = fa[i - n][0] + n;
	for(int k = 1;k <= 20;++k)for(int i = 1;i <= 2 * n;++i)fa[i][k] = fa[fa[i][k - 1]][k - 1];
	int ans = 0x3f3f3f3f;
	for(int i = 1;i <= n;++i)
	{//cout << " > ";
		int pos = i;//cout << i << " : " << endl;
		int res = 0;
		for(int k = 20;k >= 0;--k)
		{
			if(fa[pos][k] == 0)continue;
			if(s[fa[pos][k]].r - s[i].l + 1 < len)
			{//cout << pos << " " << k << " " << fa[pos][k] << endl;
				pos = fa[pos][k];
				res += (1 << k);
			}
		}//cout << "-> " << s[fa[pos][0]].r - s[i].l << endl;
		if(s[fa[pos][0]].r - s[i].l + 1 >= len)ans = min(ans,res + 2);//cout << " : " << res << " " << i << endl << endl;
	}
	if(ans < 0x3f3f3f3f)cout << ans << endl;
	else puts("impossible");
	return 0;
}
 posted on 2020-08-21 21:18  15101051  阅读(139)  评论(0编辑  收藏  举报