Description
给一个环 (n) 个区间,求最小用几个区间覆盖环。
(1leqslant nleqslant 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;
}