【倍增】ABC212F Greedy Takahashi 题解

发布时间 2023-10-07 13:37:57作者: Pengzt

ABC212F

暴力就是直接跳,显然不可过。

考虑对暴力进行优化,发现整个图是不会改变的,容易想到使用倍增。

显然是对边进行倍增的,令 \(f_{i, j}\) 表示从第 \(i\) 条边开始,跳了 \(2^j\) 条边后,到的是哪一条边,如果不存在,则设为 \(-1\)

然后就是很显然的倍增了,最后讨论一下即可。

时间复杂度:\(\mathcal{O}((m + Q) \log m)\)

代码:

const int N = 1e5 + 10;
int n, m, Q;
int f[N][20];
set<pii> v[N];
typedef set<pii>::iterator iter;
struct edge {
	int u, v, s, t;
} e[N];

int get(int u, int val) {
	iter it = v[u].lower_bound(mkp(val, 0));
	if (it == v[u].end()) return -1;
	return (*it).second;
}

int main() {
	ios
	for (int i = 0; i < N; i++) for (int j = 0; j < 20; j++) f[i][j] = -1;
	cin >> n >> m >> Q;
	for (int i = 1; i <= m; i++) {
		cin >> e[i].u >> e[i].v >> e[i].s >> e[i].t;
		v[e[i].u].insert(make_pair(e[i].s, i));
	}
	for (int i = 1; i <= m; i++) {
		f[i][0] = get(e[i].v, e[i].t);
	}
	for (int j = 1; j <= 19; j++)
		for (int i = 1; i <= m; i++)
			if (f[i][j - 1] != -1)
				f[i][j] = f[f[i][j - 1]][j - 1];
	while (Q--) {
		int x, y, z; cin >> x >> y >> z;
		int now = get(y, x);
		if (now == -1) {
			cout << y << "\n";
			continue;
		}
		for (int i = 19; i >= 0; i--)
			if (f[now][i] != -1 && e[f[now][i]].s < z)
				now = f[now][i];
		if (z <= e[now].s) cout << e[now].u << "\n";
		else if (e[now].t < z) cout << e[now].v << "\n";
		else cout << e[now].u << " " << e[now].v << "\n";
	}
	return 0;
}