题意:给一个环和多个区间,且不存在被包含区间,求在已选定第 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; }