[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 }

 

posted @ 2018-12-02 17:57  HocRiser  阅读(162)  评论(0编辑  收藏  举报