国旗计划 省选

SCOI2015 省选] 国旗计划

1_280.png

手搓 模拟的数据

这题做重要的 首先是 有化圆为链的思想,讲给的区间 化为链式,也就是说讲 l > r的地方的r + m ,相当于 多走了一圈,所以需要 将环复制一遍 ,在加倍身长为 一条链;

#include <bits/stdc++.h>
using namespace std;
const int N = 1e6 + 10;
int go[N][20];//倍增数组, go[s][i]表示从s区间开始 跳2^i步的区间;
int res[N]; // 记录答案;
int n , m;

struct edge
{
    int id;
    int l;
    int r;
    bool operator < (const edge & rhs) const
    {
        if(l != rhs.l) return l < rhs.l;
        return r < rhs.r;
    }
}w[N];

void pre()
{
    for(int i = 1 , p = i ; i <= n * 2 ; i ++)
    {
        while(p <= n * 2 && w[p].l <= w[i].r) p ++;
        
        go[i][0] = p - 1; //如果不-1那么这个p不符合上面的这个条件;
    }
    
    for(int i = 1 ; i < 20 ; i ++)
    {
        for(int j = 1 ; j <= n * 2 ; j ++)
        {
            go[j][i] = go[go[j][i - 1]][i - 1];
        }
    }
}

void query(int k)
{
    int len = w[k].l + m;
    int ans = 1;
    int p = k;
    
    for(int i = 19 ; i >= 0 ; i --)
    {
        if(go[k][i] != 0 && w[go[k][i]].r < len)
        {
            ans += (1 << i);
            k = go[k][i];
        }
    }
    res[w[p].id] = ans + 1; // 因为上面是 < len 所以还达不到 , 所以需要再加上最后一个人;
}

int main()
{
    cin >> n >> m;
    
    for(int i = 1 ; i <= n ; i ++) //进行拆圆化为链式;
    {
        cin >> w[i].l >> w[i].r;
        w[i].id = i;
        
        if(w[i].l > w[i].r) w[i].r += m;
    }
    
    sort(w + 1 , w + 1 + n);
    //复制环 加倍身长的代码,是化圆为链的核心代码;
    for(int i = 1 ; i <= n ; i ++)
    {
        w[i + n] = w[i];
        w[i + n].l += m;
        w[i + n].r += m;
    }
    
    pre(); //进行预处理;
    
    for(int i = 1 ; i <= n ; i ++) query(i); // 进行查询;
    
    for(int i = 1 ; i <= n ; i ++) cout << res[i] << " ";
    
    return 0;
}
posted @ 2024-01-27 20:26  不过是过客  阅读(10)  评论(0编辑  收藏  举报