破环为链,并且将链延长一倍就不用考虑C>d了,并且题目说每个战士的奔袭区间都不被包含,所以以左端点排序后,注意到右端点必定单调,这就可以用贪心思想了,让下一个战士能尽可能远,只需要左端点尽可能远,不过要满足左端点在前一个战士的右端点前。第一个想法是暴力,显然会超时,就算用二分查找也会超时(别问我怎么知道的www),所以就考虑用倍增思想,构造一个dp[i][j],i表示低i个战士,j表示传递2j个战士最远的战士编号,所以可以得到递推关系式dp[i][j]=dp[dp[i][j-1]][j-1],初始化dp[i][0]可以用二分查找。最后j从19逆序遍历,满足条件次数就加上2j,最后别忘了在加上他自己。
`#include<stdio.h>
include
include
include<stdlib.h>
using namespace std;
const int N=4e5+7;
int dp[400007][20]={0};
struct soldiers{
int a;
int b;
int id;
} lst[N];
int erfen(struct soldiers* lst,int l,int r,int t){
while(l<=r){
int m=(l+r)/2;
if(lst[m].a>t){
r=m-1;
}
else{
l=m+1;
}
}
return r;
}
int main(){
int n,m,a,b;
int times[N]={0};
scanf("%d %d",&n,&m);
for(int i=0;i<n;i++){
scanf("%d %d",&a,&b);
if(a>b) b+=m;
lst[i].a=a;
lst[i].b=b;
lst[i].id=i;
}
sort(lst,lst+n,[](const soldiers& a,const soldiers& b){
return a.a<b.a;
});
for(int i=0;i<n;i++){
lst[i+n].a=lst[i].a+m;
lst[i+n].b=lst[i].b+m;
lst[i+n].id=lst[i].id;
}
for(int i=0;i<2n;i++){
int x=erfen(lst,i+1,2n-1,lst[i].b);
dp[i][0]=x;
}
for(int j=1;j<20;j++){
for(int i=0;i<2*n;i++){
dp[i][j]=dp[dp[i][j-1]][j-1];
}
}
for(int i=0;i<n;i++){
int end=lst[i].a+m,p=i;
for(int j=19;j>=0;j--){
if(lst[dp[p][j]].b<end){
times[lst[i].id]+=(1<<j);
p=dp[p][j];
}
}
}
for(int i=0;i<n;i++){
printf("%d ",times[i]+2);
}
return 0;
} `