[SCOI2015]国旗计划
注意一个关键点,没有一个区间是包含在另一个区间的,这意味着区间之间要么相交要么相离,
当有一个区间一定加入时,我们可以二分查找去得到下一个区间的,但是这样速度显然太慢了,所以我们利用倍增来优化。
定义表示
号节点为左端点,共有
条线段连在一起最有可到达的坐标。
然后只需要从小到大初始化数组,从大到小枚举选择就行了。
/*
Author : lifehappy
*/
#include <bits/stdc++.h>
using namespace std;
const int N = 1e6 + 10;
int n, m, tot, cnt, b[N], id[N][25];
struct segment {
int l, r;
segment(int _l = 0, int _r = 0) : l(_l), r(_r) {}
bool operator < (const segment &t) const {
return l < t.l;
}
}a[N], la[N];
inline int ID(int x) {
return lower_bound(b + 1, b + 1 + cnt, x) - b;
}
int main() {
// freopen("in.txt", "r", stdin);
// freopen("out.txt", "w", stdout);
// ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
scanf("%d %d", &n, &m);
for(int i = 1; i <= n; i++) {
int l, r;
scanf("%d %d", &l, &r);
a[i] = segment(l, r);
if(r < l) la[++tot] = segment(l, r + m), la[++tot] = segment(l + m, 2 * m);
else la[++tot] = segment(l, r), la[++tot] = segment(l + m, r + m);
}
for(int i = 1; i <= tot; i++) {
b[++cnt] = la[i].l;
b[++cnt] = la[i].r;
}
sort(b + 1, b + 1 + cnt), sort(la + 1, la + tot + 1);
cnt = unique(b + 1, b + 1 + cnt) - (b + 1);
int pos = 1, maxr = 0;
for(int i = 1; i <= cnt; i++) {
while(pos <= tot && la[pos].l <= b[i]) {
maxr = max(maxr, la[pos].r);
pos++;
}
id[i][0] = ID(maxr);//我们一定是找一个最大右端点,这样才是最优的。
}
for(int k = 1; k <= 20; k++) {
for(int i = 1; i <= cnt; i++) {
id[i][k] = id[id[i][k - 1]][k - 1];
}
}
for(int i = 1; i <= n; i++) {
int l = a[i].l, r = a[i].r, target, res = 1;
if(l > r) r += m;
r = ID(r), target = l + m;
for(int k = 20; k >= 0; k--) {
if(b[id[r][k]] < target) {
res += (1 << k);
r = id[r][k];
}
}
res++;
printf("%d%c", res, i == n ? '\n' : ' ');
}
return 0;
} 
京公网安备 11010502036488号