NC20302 国旗计划(倍增)

首先破环成链,因为图中是一个环,所以转化成有n种可能性的链。

输入如果右端点小,就+m

一个显然的贪心是,既然选择当前点,那么下一个点的左端点越靠近当前点的右端越好

这个成立的原因是,没有两个线段存在包含关系,因此左端点越右,右端点越右,这样覆盖的会尽可能的远。

之后就可以用倍增优化进行跳跃,直到覆盖当前点所对应的这条链

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<int,int> pll;
const int N=4e5+10;
const int mod=1e9+7;
struct node{
    int l,r;
    int id;
}s[N];
int f[N][25];
int n,m;
int ans[N];
bool cmp(node a,node b){
    return a.l<b.l;
}
void init(){
    int now=1;
    int i,j;
    for(i=1;i<=2*n;i++){
        while(s[now].l<=s[i].r&&now<=2*n){
            now++;
        }
        f[i][0]=now-1;
    }
    for(j=1;j<=20;j++){
        for(i=1;i<=2*n;i++){
            f[i][j]=f[f[i][j-1]][j-1];
        }
    }
}
void solve(int x){
    int d=s[x].l+m;
    int res=1;
    int tmp=x;
    int i;
    for(i=20;i>=0;i--){
        if(f[x][i]!=0&&s[f[x][i]].r<d){
            res+=(1<<(i));
            x=f[x][i];
        }
    }
    ans[s[tmp].id]=res+1;
}
int main(){
    ios::sync_with_stdio(false);
    int i;
    cin>>n>>m;
    for(i=1;i<=n;i++){
        cin>>s[i].l>>s[i].r;
        if(s[i].l>s[i].r){
            s[i].r+=m;
        }
        s[i].id=i;
    }
    sort(s+1,s+1+n,cmp);
    for(i=1;i<=n;i++){
        s[i+n]=s[i];
        s[i+n].l+=m;
        s[i+n].r+=m;
    }
    init();
    for(i=1;i<=n;i++){
        solve(i);
    }
    for(i=1;i<=n;i++)
        cout<<ans[i]<<" ";
    cout<<endl;
    return 0;
}
View Code

 

posted @ 2021-04-10 09:07  朝暮不思  阅读(81)  评论(0编辑  收藏  举报