Luogu P4768 [NOI2018]歸程
阿新 • • 發佈:2019-03-18
ont void tps init 最短 初始 ref min prior
題目鏈接 \(Click\) \(Here\)
\(Kruskal\)重構樹的好題。想到的話就很好寫,想不到亂搞的難度反而相當高。
按照點的水位,建出來滿足小根隊性質的\(Kruskal\)重構樹,這樣一個點的子樹裏的點就是所有可以開車到達的點。做一遍最短路預處理,然後樹上求一個子樹\(min\),就可以得到子樹裏面的點到點\(1\)的最短距離。註意需要初始化。
#include <bits/stdc++.h> using namespace std; const int N = 800010; const int INF = 0x7fffffff; struct _edge {int u, v, l, a;}_e[N]; bool cmp (_edge lhs, _edge rhs) { return lhs.a > rhs.a; } struct Graph { int cnt, head[N]; struct edge { int nxt, to, w; }e[N << 1]; void Init () { cnt = 0; memset (head, 0, sizeof (head)); } void add_edge (int u, int v, int w) { e[++cnt] = (edge) {head[u], v, w}; head[u] = cnt; } }G, krus; int read () { int s = 0, w = 1, ch = getchar (); while ('9' < ch || ch < '0') { if (ch == '-') w = -1; ch = getchar (); } while ('0' <= ch && ch <= '9') { s = s * 10 + ch - '0'; ch = getchar (); } return s * w; } int T, n, m, Q, K, S, tot, fa[N], _high[N]; int find (int x) { return fa[x] == x ? x : fa[x] = find (fa[x]); } int deep[N], fafa[N][20]; int dis[N], mindis[N]; void dfs (int u, int fa) { fafa[u][0] = fa; mindis[u] = krus.head[u] == 0 ? dis[u] : INF; deep[u] = deep[fa] + 1; for (int i = 1; (1 << i) <= deep[u]; ++i) { fafa[u][i] = fafa[fafa[u][i - 1]][i - 1]; } for (int i = krus.head[u]; i; i = krus.e[i].nxt) { int v = krus.e[i].to; dfs (v, u); mindis[u] = min (mindis[u], mindis[v]); } } void kruskal () { sort (_e + 1, _e + 1 + m, cmp); tot = n; for (int i = 1; i <= n; ++i) fa[i] = i; for (int i = 1; i <= m; ++i) { int u = find (_e[i].u); int v = find (_e[i].v); if (u != v) { int T = ++tot; _high[T] = _e[i].a; krus.add_edge (T, u, 0); krus.add_edge (T, v, 0); fa[T] = fa[u] = fa[v] = T; } } dfs (tot, 0); } struct Node { int pos, dis; bool operator < (Node rhs) const { return dis > rhs.dis; } }; priority_queue <Node> q; void dijkstra () { for (int i = 1; i <= n; ++i) dis[i] = i == 1 ? 0 : INF; q.push ((Node) {1, 0}); while (!q.empty ()) { Node u = q.top (); q.pop (); if (dis[u.pos] < u.dis) continue; for (int i = G.head[u.pos]; i; i = G.e[i].nxt) { int v = G.e[i].to; if (dis[v] > dis[u.pos] + G.e[i].w) { dis[v] = dis[u.pos] + G.e[i].w; q.push ((Node) {v, dis[v]}); } } } } int query (int u, int p) { //u 出發節點 p 水位線 for (int i = 19; i >= 0; --i) { if (_high[fafa[u][i]] > p) { u = fafa[u][i]; } } // printf ("u = %d\n", u); return mindis[u]; } void Init () { G.Init (); krus.Init (); memset (fafa, 0, sizeof (fafa)); memset (_high, 0, sizeof (_high)); memset (mindis, 0, sizeof (mindis)); } int main () { //freopen ("data.in", "r", stdin); T = read (); while (T--) { Init (); printf ("T = %d\n", T); n = read (), m = read (); for (int i = 1; i <= m; ++i) { _e[i].u = read (); _e[i].v = read (); _e[i].l = read (); _e[i].a = read (); G.add_edge (_e[i].u, _e[i].v, _e[i].l); G.add_edge (_e[i].v, _e[i].u, _e[i].l); //建雙向邊 } int lastans = 0; dijkstra (); kruskal (); Q = read (), K = read (), S = read (); for (int i = 1; i <= Q; ++i) { static int v, p, v0, p0; v0 = read (), p0 = read (); v = (v0 + K * lastans - 1) % n + 1; p = (p0 + K * lastans) % (S + 1); printf ("%d\n", lastans = query (v, p)); } } }
Luogu P4768 [NOI2018]歸程