usingnamespace std; constint N = 2e5 + 10, M = 2 * N; structNode { int id; int L; int R; };
int n, m, n2; Node w[M]; int res[N], fa[M][20];
boolcmp(Node A, Node B){ return A.L < B.L ; }
voidinit(){ int nxt = 1; for (int i = 1; i <= n2; i++){ // nxt = i; while(nxt <= n2 && w[nxt].L <= w[i].R) { nxt++; } fa[i][0] = nxt - 1; // 记录走一次可以走到的最优解位置,这里还运用到了一点贪心思路,按照一般思路,这里nxt在每次遍历的时候都应该进行一个初始化操作nxt = i的,但是我们可以推出不需要进行这一步操作的,为什么呢?我们可以先这样思考,我们的nxt如果出现回溯的情况这代表着什么呢,实际上代表的是我们枚举的这个区间和上一个区间是不是就出现了包含关系比如思路的那张图,只有这种情况才会出现nxt回溯的情况,但是由标红自体可知这是不可能出现的,换句话就是这道题目所有的区间按照左端点从小到大排序好之后右端点是单调递增。
}
// ST递增算法的具体体现,本题最难的地方,这个地方的讲解之后会更新。 for (int i = 1; (1 << i) <= n; i++) { for (int s = 1; s <= n2; s++) { fa[s][i] = fa[fa[s][i - 1]][i - 1]; } } }
voidgetans(int x){ int len = w[x].L + m, cur = x, ans = 1; for (int i = log2(N); i >= 0; i--){ int pos = fa[cur][i]; if (pos && w[pos].R < len) { ans += 1 << i; cur = pos; } } res[w[x].id] = ans + 1; } intmain() { ios::sync_with_stdio(false),cin.tie(0),cout.tie(0); cin >> n >> m; for (int i = 1; i <= n; i++){ w[i].id = i; cin >> w[i].L >> w[i].R; if (w[i].L > w[i].R) w[i].R += m; }
sort(w + 1, w + n + 1, cmp); n2 = n; for (int i = 1; i <= n; i++) { n2++; w[n2] = w[i]; w[n2].L = w[i].L + m; w[n2].R = w[i].R + m; }
init();
for (int i = 1; i <= n; i++) getans(i); for (int i = 1; i <= n; i++) cout << res[i] << " "; return0; }