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; }
没有人不辛苦,只有人不喊疼