题意
给你一个环,有 个区间,区间之间互相不覆盖。求当任意一个区间必须选择时,最少需要多少个区间能够覆盖整个环。
思路
对于一个战士 ,如果选了他,那么下一个战士
一定是所有左端点小于等于
的右端点的战士中最大的一个战士,因为这样子才是是最优的。所以我们只需要预处理加二分找到下一个战士就好了。然后一个一个的找有点慢,所以就用倍增优化一下就好。
代码
#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是因为没有计算第一个和最后一个。

京公网安备 11010502036488号