Link
Diffculty
算法难度5,思维难度6,代码难度5
Description
给定一个长度为 m m m的环,环上有 m m m个点 [ 1 , m ] [1,m] [1,m],以及 n n n个互不包含的区间。
要求对于每个区间求出,在必须选这个区间的前提下,能使得所有被选区间覆盖整个环的最少区间数。
1 ≤ n ≤ 2 × 1 0 5 , m < 1 0 9 1\le n\le 2\times 10^5,m<10^9 1≤n≤2×105,m<109
Solution
首先区间互不包含,那么我们将所有区间按照左端点排序之后,区间一定满足左端点和右端点同时严格递增。
破环成链之后,这样我们可以二分或者递推求出选每个区间的下一个最优选择区间。
求出来之后,比如第 i i i个区间的下一个最优区间是 f ( i ) f(i) f(i),那么就从 f ( i ) f(i) f(i)向 i i i连一条边。
这样我们倍增预处理每个点的 2 j 2^j 2j级祖先,查询的时候就固定这个区间开始,限制不能再跳过这个区间的左端点,然后直接倍增跳就好了,最后加上没有算的这两个区间。
时间复杂度 O ( n l o g n ) O(nlogn) O(nlogn)
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<iostream>
#include<algorithm>
#define LL long long
using namespace std;
inline int read(){
int x=0,f=1;char ch=' ';
while(ch<'0' || ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0' && ch<='9')x=x*10+(ch^48),ch=getchar();
return f==1?x:-x;
}
const int N=4e5+5;
struct data{
int l,r,id;
data(){}
data(int _l,int _r,int _id):l(_l),r(_r),id(_id){}
inline bool operator < (const data& b) const {
return l<b.l;
}
}a[N];
int n,m,c[N],d[N],tot,fa[N][19],ans[N];
int main(){
n=read();m=read();
for(int i=1;i<=n;++i){
int l=read(),r=read();
if(r<l)r+=m;
a[++tot]=data(l,r,i);
a[++tot]=data(l+m,r+m,0);
}
sort(a+1,a+tot+1);
for(int i=1;i<tot;++i){
int l=i+1,r=tot,mid;
while(l<r){
mid=(l+r+1)>>1;
if(a[mid].l<=a[i].r)l=mid;
else r=mid-1;
}
fa[i][0]=l;
}
for(int k=1;k<=18;++k)
for(int i=1;i<=tot;++i)
fa[i][k]=fa[fa[i][k-1]][k-1];
for(int i=1;i<=tot;++i){
if(!a[i].id)continue;
int x=i,L=a[i].l+m;
for(int j=18;j>=0;--j)
if(fa[x][j] && a[fa[x][j]].r<L)
x=fa[x][j],ans[a[i].id]+=(1<<j);
}
for(int i=1;i<=n;++i)printf("%d ",ans[i]+2);
return 0;
}