「NOIP 模拟赛 20230706」轨道飞跃

发布时间 2023-07-06 19:24:53作者: ClapEcho233

summarization

solution

考虑倒着走,那么从 \(u\) 走到 \(v\) 条件就变为 \(r_v\)\(u\) 所在的区间内,于是我们预处理出右端点在这段区间内的轨道的左端点的最小值(可以用 ST 表),然后从 \(t\) 跳回 \(s\)

不难发下,往回跳的过程可以用倍增优化(具体见代码),最终复杂度 \(\mathcal{O}(n\log n)\)

code

#define pii pair<int,int>
#define fi first
#define se second
#define mk make_pair
CI N = 1e5, LGN = 20, INF = 0x7fffffff; int n, m; pii a[N + 5], RMQ[N + 5][LGN + 5]; int lsh[N + 5], pre[N + 5][LGN + 5], lg[N * 2 + 5];
int main () {
	RI i, j; for (Read (n, m), i = 1; i <= n; ++ i) Read (a[i].fi, a[i].se), lsh[i] = a[i].se; sort (lsh + 1, lsh + n + 1);
	int cnt = unique (lsh + 1, lsh + n + 1) - lsh - 1; for (i = 1; i <= n; ++ i) RMQ[i][0] = mk (INF, -1); 
	for (i = 1; i <= n; ++ i) {int emm = lower_bound (lsh + 1, lsh + cnt + 1, a[i].se) - lsh; RMQ[emm][0] = min (RMQ[emm][0], mk (a[i].fi, i));}
	for (j = 1; j <= LGN; ++ j) for (i = 1; i <= n - (1 << j) + 1; ++ i) RMQ[i][j] = min (RMQ[i][j - 1], RMQ[i + (1 << (j - 1))][j - 1]);
	for (i = 2; i <= n * 2; ++ i) lg[i] = lg[i >> 1] + 1; for (i = 1; i <= n; ++ i) {
		int l = lower_bound (lsh + 1, lsh + cnt + 1, a[i].fi) - lsh, r = lower_bound (lsh + 1, lsh + cnt + 1, a[i].se) - lsh;
		int k = lg[r - l + 1]; pre[i][0] = min (RMQ[l][k], RMQ[r - (1 << k) + 1][k]).se;
	} for (j = 1; j <= LGN; ++ j) for (i = 1; i <= n; ++ i) pre[i][j] = pre[pre[i][j - 1]][j - 1]; W (m --) {
		int x, y; Read (x, y); if (x == y || (a[y].fi <= a[x].se && a[x].se <= a[y].se)) {printf ("%d\n", x != y); continue;} int num = 0;
		for (i = LGN; i >= 0; -- i) if (a[x].se < a[pre[y][i]].fi) num += 1 << i, y = pre[y][i]; y = pre[y][0]; ++ num;
		if (a[x].se < a[y].fi || a[x].se > a[y].se) printf ("impossible\n"); else printf ("%d\n", num + (a[x].se >= a[y].fi));
	}
	return 0; 
}