AtCoder Beginner Contest 212 F Greedy Takahashi

洛谷传送门

AtCoder 传送门

考虑每条边,因为是静态的,所以可以预处理出 \(f_{i,j}, g_{i,j}\) 表示从第 \(i\) 条边,往后跳 \(2^j\) 条边,跳到边的编号和目前的时间(如果不存在就当作跳到第 \(0\) 条边)。直接倍增处理即可。

询问就是找到从 \(u\) 开始的出边,能跳尽量跳。

注意一些细节。

code
// Problem: F - Greedy Takahashi
// Contest: AtCoder - AtCoder Beginner Contest 212
// URL: https://atcoder.jp/contests/abc212/tasks/abc212_f
// Memory Limit: 1024 MB
// Time Limit: 4000 ms
// 
// Powered by CP Editor (https://cpeditor.org)

#include <bits/stdc++.h>
#define pb emplace_back
#define fst first
#define scd second
#define mems(a, x) memset((a), (x), sizeof(a))

using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef double db;
typedef long double ldb;
typedef pair<ll, ll> pii;

const int maxn = 100100;
const int logn = 20;

ll n, m, q, f[maxn][logn], g[maxn][logn];

struct E {
	ll v, s, t, id;
	E(ll a = 0, ll b = 0, ll c = 0, ll d = 0) : v(a), s(b), t(c), id(d) {}
};

inline bool cmp(E a, E b) {
	return a.s < b.s;
}

struct node {
	ll u, v, s, t;
	node(ll a = 0, ll b = 0, ll c = 0, ll d = 0) : u(a), v(b), s(c), t(d) {}
} a[maxn];

vector<E> G[maxn];
vector<pii> qq[maxn];

void solve() {
	scanf("%lld%lld%lld", &n, &m, &q);
	for (int i = 1, u, v, s, t; i <= m; ++i) {
		scanf("%d%d%d%d", &u, &v, &s, &t);
		G[u].pb(v, ++s, t, i);
		a[i] = node(u, v, s, t);
	}
	for (int i = 1; i <= n; ++i) {
		sort(G[i].begin(), G[i].end(), cmp);
	}
	f[0][0] = 0;
	g[0][0] = 1e18;
	for (int u = 1; u <= n; ++u) {
		for (E e : G[u]) {
			ll v = e.v, t = e.t;
			int l = 0, r = (int)G[v].size() - 1, pos = -1;
			while (l <= r) {
				int mid = (l + r) >> 1;
				if (G[v][mid].s > t) {
					pos = mid;
					r = mid - 1;
				} else {
					l = mid + 1;
				}
			}
			if (pos == -1) {
				f[e.id][0] = 0;
				g[e.id][0] = 1e18;
			} else {
				f[e.id][0] = G[v][pos].id;
				g[e.id][0] = G[v][pos].t;
			}
		}
	}
	for (int j = 1; j <= 18; ++j) {
		for (int i = 0; i <= m; ++i) {
			f[i][j] = f[f[i][j - 1]][j - 1];
			g[i][j] = g[f[i][j - 1]][j - 1];
		}
	}
	while (q--) {
		ll u, x, y;
		scanf("%lld%lld%lld", &x, &u, &y);
		int l = 0, r = (int)G[u].size() - 1, pos = -1;
		while (l <= r) {
			int mid = (l + r) >> 1;
			if (G[u][mid].s > x) {
				pos = mid;
				r = mid - 1;
			} else {
				l = mid + 1;
			}
		}
		if (pos == -1) {
			printf("%lld\n", u);
			continue;
		}
		if (y < G[u][pos].s) {
			printf("%lld\n", u);
			continue;
		}
		if (y <= G[u][pos].t) {
			printf("%lld %lld\n", u, G[u][pos].v);
			continue;
		}
		int d = G[u][pos].id;
		for (int i = 18; ~i; --i) {
			if (g[d][i] < y) {
				d = f[d][i];
			}
		}
		if (!f[d][0]) {
			printf("%lld\n", a[d].v);
			continue;
		}
		int k = f[d][0];
		if (y < a[k].s) {
			printf("%lld\n", a[k].u);
		} else if (a[k].s <= y && y <= a[k].t) {
			printf("%lld %lld\n", a[k].u, a[k].v);
		}
	}
}

int main() {
	int T = 1;
	// scanf("%d", &T);
	while (T--) {
		solve();
	}
	return 0;
}

posted @ 2023-05-18 15:25  zltzlt  阅读(31)  评论(0编辑  收藏  举报