国旗计划 省选
SCOI2015 省选] 国旗计划
手搓 模拟的数据
这题做重要的 首先是 有化圆为链的思想,讲给的区间 化为链式,也就是说讲 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;
}