LuoGu4155/BZOJ4444

贪心+倍增

对于一个环,套路性问题,我们直接拆开加倍,拉成链即可。

首先对于一个战士$i$,如果选了他,那么下一个战士$j$一定是所有左端点小于等于i的右端点的战士中最大的一个战士,因为这样子是最优的。

对于一个战士的下一个是哪一个的话,预处理+二分查找一下就可以了。

然后我们就直接一个一个的走就可以了。

但是我们为什么不倍增的跳呢??

于是将一个一个跳变为倍增跳,,问题就解决了。。。

代码

#include <bits/stdc++.h>
#define R register
#define eps 1e-12
#define INF (1<<30)
#define LL long long
#define LINF (1ll<<60)
#define MM(x, y) memset(x, y, sizeof x)
#define Fo(i, x, y) for(R int i=x; i<=y; ++i)
#define Ro(i, x, y) for(R int i=x; i>=y; --i)
using namespace std;
template<typename T> inline T Max(R T x, R T y) {return x > y ? x : y;}
template<typename T> inline T Min(R T x, R T y) {return x < y ? x : y;}
template<typename T> inline void in(R T &x)
{
    static int ch; static bool flag;
    for(flag=false, ch=getchar(); ch<'0'||ch>'9'; ch=getchar()) flag |= ch=='-';
    for(x=0; ch>='0'&&ch<='9'; ch=getchar()) x = (x<<1) + (x<<3) + ch - '0';
    x = flag ? -x : x;
}
/*************************************Samle*************************************/

int n, m;
struct node{int l, r, id;} peo[800005];

namespace First
{
    int f[800005][31], s[800005][31], ans[800005], p;
    inline bool cmp(R node x, R node y) {return x.l < y.l || (x.l == y.l && x.r < y.r);}
    inline int find(R int x, R int l, R int r)
    {
        R int re=p+1, mid;
        while(l <= r)
        {
            mid = (l + r) >> 1;
            if(peo[mid].l <= x) l = mid + 1, re = mid;
            else r = mid - 1;
        }
        return re;
    }
    inline void calc()
    {
        p = n; MM(ans, 0);
        Fo(i, 1, n) if(peo[i].l > peo[i].r) peo[i].r += m; else peo[++p].l = peo[i].l + m, peo[p].r = peo[i].r + m, peo[p].id = i;
        sort(peo+1, peo+p+1, cmp); peo[p+1].r = 2e9;
        Fo(i, 0, 30) Fo(j, 1, p+1) f[j][i] = p+1;
        Fo(i, 1, p) f[i][0] = find(peo[i].r, i+1, p+1);
        Fo(j, 1, 30) Fo(i, 1, p) f[i][j] = f[f[i][j-1]][j-1];
        Fo(i, 1, p)
        {
            if(peo[i].id && !ans[peo[i].id])
            {
                R int now = i, to = peo[i].l + m;
                Ro(j, 30, 0) if(peo[f[now][j]].r < to) now = f[now][j], ans[peo[i].id] += (1<<j);
            }
        }
        Fo(i, 1, n) printf("%d ", ans[i]+2); puts("");
        // ans+2 -> ans中没有算第一个人,也没有算最后一个人,所以要加2
    }
}

int main()
{
    in(n); in(m);
    Fo(i, 1, n) in(peo[i].l), in(peo[i].r), peo[i].id = i;
    First :: calc();
    return 0;
}

 

posted @ 2018-04-15 18:00  諾-Oier  阅读(137)  评论(0)    收藏  举报