题意:给一个环和多个区间,且不存在被包含区间,求在已选定第 i个区间时( i 属于 ( 1,n ) ),总共需要多少段区间才可将整个环给覆盖完;
解法:贪心+倍增;
1.贪心;区间覆盖问题的较常见的一个解决思路就是按端点排序,如果是环的话,还要断环为链;
1.贪心;题目中说到不存在被包含区间,即不存在任意两个区间,使得其中的一个区间被另一个区间包含,那么我们可以知道不会有任意两条线段的同一边的端点重合,所以我们就可以在排完序后进行倍增预处理;设 f[i][j]为第 i条线段跳了 2^j步后可以到达的线段序号,在处理的时候,要注意一下边界;
附上代码:
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<vector>
#include<map>
#define ll long long
#define rg register
using namespace std;
const int N = 4e5+10;
inline int read(){
int ref=0,x=1;char ch=getchar();
while(!isdigit(ch)) ch=getchar();
while(isdigit(ch)) ref=ref*10+ch-'0',ch=getchar();
return ref*x;
}
int n,m;
struct node{
int l,r,id;
}a[N];
int f[N][20],rel[N>>1];
bool cmp(node a,node b){
return a.l<b.l;
}
void prepare(){
int limit=2*n;
for(int i=1,pos=i;i<=limit;++i){
while(pos<=limit&&a[pos].l<=a[i].r) pos++;
f[i][0]=pos-1;
}
for(rg int j=1;j<20;++j)
for(rg int i=1;i<=limit;++i) f[i][j]=f[f[i][j-1]][j-1];
}
void deal(int x){
int end=a[x].l+m,ans=1,fina=x;
for(rg int i=19;i>=0;i--){
int pre=f[x][i];
if(a[pre].r<end) ans+=(1<<i),x=pre;
}
rel[a[fina].id]=ans+1;
}
int main()
{
n=read(),m=read();
for(rg int i=1;i<=n;++i){
a[i].l=read(),a[i].r=read();
if(a[i].l>a[i].r) a[i].r+=m;
a[i].id=i;
}
sort(a+1,a+n+1,cmp);
for(rg int i=1;i<=n;++i){
a[i+n]=a[i];
a[i+n].l=a[i].l+m;
a[i+n].r=a[i].r+m;
}
prepare();
for(rg int i=1;i<=n;++i) deal(i);
for(rg int i=1;i<=n;++i) printf("%d ",rel[i]);
return 0;
}