[ SCOI 2015 ] 国旗计划

题目

Luogu
Acwing
LOJ

思路

1.png
2.png
3.png

代码

#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;
}
posted @ 2021-04-06 17:47  Protein_lzl  阅读(74)  评论(0编辑  收藏  举报