SCOI2015 国旗计划

题目链接:

断环为链,将环复制两倍。

用to[i][j]表示从点i出发,走\(2^j\)步能够到达的最远的(右端点qwq)的编号。

注意为了方便判断已经走了一圈了,我们最后一步先不要跳,只需要判断当前右端点仍在i+n之前即可。然后这个样子的话,最后答案需要+1。

代码如下:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#define MAXN 400010
using namespace std;
int n,m;
int to[MAXN][22];
struct Node{int l,r,id,ans;}t[MAXN];
inline bool cmp(struct Node x,struct Node y)
{
    if(x.l!=y.l) return x.l<y.l;
    return x.r<y.r;
}
inline bool cmp1(struct Node x,struct Node y){return x.id<y.id;}
int main()
{
    #ifndef ONLINE_JUDGE
    freopen("ce.in","r",stdin);
    #endif
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++)
    {
        scanf("%d%d",&t[i].l,&t[i].r);
        if(t[i].r<t[i].l) t[i].r+=m;
        t[i].id=i;
    }
    for(int i=n+1;i<=2*n;i++)
    {
        t[i].l=t[i-n].l+m;
        t[i].r=t[i-n].r+m;
        t[i].id=i;
    }
    sort(&t[1],&t[n*2+1],cmp);
    int pos=1;
    for(int i=1;i<=n*2;i++)
    {
        while(pos<2*n&&t[pos+1].l<=t[i].r) pos++;
        to[i][0]=pos;
    }
    for(int j=1;j<=21;j++)
        for(int i=1;i<=2*n;i++)
            to[i][j]=to[to[i][j-1]][j-1];
    for(int i=1;i<=n;i++)
    {
        int now=i,cur_ans=1;
        for(int j=21;~j;j--)
        {
            if(to[now][j]<i+n)
            {
                cur_ans+=(1<<j),now=to[now][j];
                //printf("cur_ans=%d now=%d\n",cur_ans,now);
            }
        }
        t[i].ans=cur_ans;
    }
    sort(&t[1],&t[2*n+1],cmp1);
    for(int i=1;i<=n;i++) printf("%d ",t[i].ans);
    return 0;
}

posted @ 2019-02-28 20:27  风浔凌  阅读(170)  评论(0编辑  收藏  举报