[BZOJ4444][SCOI2015]国旗计划(倍增)
链上是经典贪心问题,将线段全按左端点排序后把点全撒在线段右端点上。这里放到环上,倍长即可。
题目保证不存在区间包含情况,于是有一种暴力做法,先将战士的管辖区间按左端点从小到大排序,对于询问x,从x战士出发,每次走到最远(管辖区间左端点最大)的一个战士,满足这个战士的区间左端点被x的区间右端点覆盖到,然后让这个战士接替x继续传递。$O(n^2)$
这显然可以倍增优化,f[i][j]表示从战士i开始共$2^j$个战士参与传递,最远可以传递到哪个战士的手中。$O(n\log n)$
1 #include<cstdio> 2 #include<algorithm> 3 #define rep(i,l,r) for (int i=(l); i<=(r); i++) 4 using namespace std; 5 6 const int N=400010; 7 int n,m,ans[N],f[N][20]; 8 9 struct P{ int l,r,id; }a[N]; 10 bool operator <(const P &a,const P &b){ return a.l<b.l; } 11 12 int main(){ 13 freopen("bzoj4444.in","r",stdin); 14 freopen("bzoj4444.out","w",stdout); 15 scanf("%d%d",&n,&m); 16 rep(i,1,n){ 17 scanf("%d%d",&a[i].l,&a[i].r); a[i].id=i; 18 if (a[i].l>a[i].r) a[i].r+=m; 19 } 20 sort(a+1,a+n+1); 21 rep(i,n+1,n*2) a[i]=(P){a[i-n].l+m,min(m*2,a[i-n].r+m),a[n-i].id}; 22 int R=1; 23 rep(i,1,n*2){ 24 while (R<n*2 && a[R+1].l<=a[i].r) R++; 25 f[i][0]=R; 26 } 27 rep(j,1,19) rep(i,1,n*2) f[i][j]=f[f[i][j-1]][j-1]; 28 rep(i,1,n){ 29 int x=i,cnt=1; 30 for (int j=19; ~j; j--) if (f[x][j]-i<n) cnt+=1<<j,x=f[x][j]; 31 ans[a[i].id]=cnt; 32 } 33 rep(i,1,n) printf("%d ",ans[i]); 34 return 0; 35 }