[ SCOI 2015 ] 国旗计划
题目
思路
代码
#include <iostream>
#include <algorithm>
using namespace std;
const int N = 400010;
int n, m, f[17][N], ans[N / 2];
struct SECTION { int l, r, id; } s[N];
bool cmp(SECTION a, SECTION b) { return a.l < b.l; }
int query(int x) {
int end = s[x].l + m, res = 0;
// 从大到小倍增
for (int i = 16, pos = x; i >= 0; i--)
// 这里是小于号, 之后最后的区间统一 + 1 就好, 否则难以处理
if (s[f[i][pos]].r < end)
pos = f[i][pos], res += (1 << i);
// 加上自己和下一个区间
return res + 2;
}
signed main() {
cin >> n >> m;
// 复制一倍接到后面
for (int i = 1; i <= n; i++) {
cin >> s[i].l >> s[i].r;
if (s[i].r < s[i].l) s[i].r += m;
s[i + n].l = s[i].l + m, s[i + n].r = s[i].r + m;
s[i].id = i, s[i + n].id = i + n;
}
sort(s + 1, s + 1 + n + n, cmp);
// 找当前区间的最优后继
for (int i = 1, j = 1; i <= n + n; i++) {
while (j <= n + n && s[j].l <= s[i].r) j++;
f[0][i] = j - 1;
}
// 倍增预处理
for (int i = 1; i <= 16; i++)
for (int j = 1; j <= n + n; j++)
f[i][j] = f[i - 1][f[i - 1][j]];
for (int i = 1; i <= n; i++) ans[s[i].id] = query(i);
for (int i = 1; i <= n; i++) cout << ans[i] << ' ';
cout << endl;
return 0;
}