拆环成链+贪心区间覆盖+倍增

好题,先插个眼,以后水平上来了再看

https://www.luogu.com.cn/problem/P4155

#include<bits/stdc++.h>
#define endl '\n'
#define lowbit(x) (x&-x)
using namespace std;
typedef long long ll;
typedef pair<int,int> pii;
typedef pair<ll,ll> pll;
const double pi=acos(-1);

const int N=4e5+5;
int n,m,tn;
struct Node{
    int id,l,r;
    bool operator < (const Node t)const {return l<t.l;}
}a[N*2];
int nxt[N][20],ans[N]; //定义nxt[s][i]为从第s个区间出发,走2^i个最优区间后到达的区间
void init(){
    int nx=1;
    // 贪心求出下一个右端点最大的区间
    for(int i=1;i<=tn;i++){
        while(nx<=tn and a[nx].l<=a[i].r){
            nx++;
        }
        nxt[i][0]=nx-1;
    }
    //  倍增,遍历区间后的第2^i个区间
    for(int i=1;(1<<i)<=n;i++){
        for(int j=1;j<=tn;j++){
            nxt[j][i]=nxt[nxt[j][i-1]][i-1]; //倍增递推式
        }
    }
}

void go(int x){ //从第x个位置出发
    int len=a[x].l+m,now=x,res=1;
    for(int i=log2(N);i>=0;i--){ //从最大i开始找
        int pos=nxt[now][i];
        if(pos and a[pos].r<len){
            res+=1<<i; //累加跳过的不优区域
            now=pos; //新位置重新开始
        }
    }
    ans[a[x].id]=res+1;
}

void solve(){
    cin>>n>>m;
    for(int i=1;i<=n;i++){
        a[i].id=i;
        cin>>a[i].l>>a[i].r;

        if(a[i].r<a[i].l) a[i].r+=m;
    }

    sort(a+1,a+n+1);
    tn=n;
    for(int i=1;i<=n;i++){
        tn++;
        a[tn]=a[i];
        a[tn].l=a[i].l+m;
        a[tn].r=a[i].r+m;
    }

    init();
    for(int i=1;i<=n;i++) go(i);
    for(int i=1;i<=n;i++) cout<<ans[i]<<" ";

}

signed main(){
    ios::sync_with_stdio(false);cin.tie(nullptr);
    int t=1;
    //cin>>t;
    while(t--) solve();
    return 0;
}


posted on 2024-11-12 20:22  TaopiTTT  阅读(3)  评论(0编辑  收藏  举报