题意

给你一个环,有 个区间,区间之间互相不覆盖。求当任意一个区间必须选择时,最少需要多少个区间能够覆盖整个环。

思路

对于一个战士 ,如果选了他,那么下一个战士 一定是所有左端点小于等于 的右端点的战士中最大的一个战士,因为这样子才是是最优的。所以我们只需要预处理加二分找到下一个战士就好了。然后一个一个的找有点慢,所以就用倍增优化一下就好。

代码

#include<bits/stdc++.h>
#define ll long long
const int N=1e6+5,INF=0x3f3f3f3f,mod=998244353;
using namespace std;

int n,m;
struct node
{
    int l,r,id;
}zs[N];
inline int read()
{
    register int x=0,f=1;char c=getchar();
    while(c<'0'||c>'9'){if(c=='-') f=-1;c=getchar();}
    while(c>='0'&&c<='9') x=(x<<3)+(x<<1)+(c^48),c=getchar();
    return x*f;
}

int qpow(int a,int b)
{
    int ans=1;
    while(b){if(b&1) ans=ans*a%mod;a=a*a%mod;b>>=1;}
    return ans;
}

int f[N][31],s[N][31],ans[N],p;
bool cmp(node x,node y){return x.l<y.l||(x.l==y.l&&x.r<y.r);}

int find(int x,int l,int r)
{
    int res=p+1,mid;
    while(l<=r)
    {
        mid=(l+r)>>1;
        if(zs[mid].l<=x) l=mid+1,res=mid;
        else r=mid-1;
    }
    return res;
}

int main()
{
    n=read();m=read();
    for(int i=1;i<=n;i++)
        zs[i].l=read(),zs[i].r=read(),zs[i].id=i;
    p=n;memset(ans,0,sizeof(ans));
    for(int i=1;i<=n;i++) 
     if(zs[i].l>zs[i].r) zs[i].r+=m;
     else zs[++p].l=zs[i].l+m,zs[p].r=zs[i].r+m,zs[p].id=i;
    sort(zs+1,zs+p+1,cmp);zs[p+1].r=2e9;
    for(int i=0;i<=30;i++) 
     for(int j=1;j<=p+1;j++) 
      f[j][i]=p+1;
    for(int i=1;i<=p;i++) f[i][0]=find(zs[i].r,i+1,p+1);
    for(int j=1;j<=30;j++) 
     for(int i=1;i<=p;i++) 
      f[i][j]=f[f[i][j-1]][j-1];
    for(int i=1;i<=p;i++)
     if(zs[i].id&&!ans[zs[i].id])
     {
        int now=i,to=zs[i].l+m;
        for(int j=30;j>=0;j--) 
         if(zs[f[now][j]].r<to) 
          now=f[now][j],ans[zs[i].id]+=(1<<j);
     }
    for(int i=1;i<=n;i++) printf("%d ",ans[i]+2);
    return 0;
}

最后答案输出时加2是因为没有计算第一个和最后一个。