|
| 1 | +/* |
| 2 | +JOI 2014 Factories |
| 3 | +- If there were very few queries, then we can do a simple tree DP to find min(dist to X + dist to Y) from each node |
| 4 | +- Notice however that the only "important" nodes we need to check are on the virtual tree from (X union Y) |
| 5 | +- We can thus construct the virtual tree for each query and then do tree DP on it to answer the query |
| 6 | +- Complexity: O(V log N) where V = sum(S + T) |
| 7 | +*/ |
| 8 | + |
| 9 | +#include "factories.h" |
| 10 | + |
| 11 | +#include <bits/stdc++.h> |
| 12 | +typedef long long ll; |
| 13 | +using namespace std; |
| 14 | + |
| 15 | +const ll INF = 1e18; |
| 16 | + |
| 17 | +vector<pair<int, ll>> graph[500000], vtree[500000]; |
| 18 | +int tin[500000], tout[500000], timer = 0, anc[500000][19]; |
| 19 | +ll to_anc[500000][19], to_X[500000], to_Y[500000]; |
| 20 | + |
| 21 | +void lca_dfs(int node = 0, int parent = -1) { |
| 22 | + tin[node] = timer++; |
| 23 | + for (int i = 1; i < 19; i++) { |
| 24 | + anc[node][i] = anc[anc[node][i - 1]][i - 1]; |
| 25 | + to_anc[node][i] = to_anc[node][i - 1] + to_anc[anc[node][i - 1]][i - 1]; |
| 26 | + } |
| 27 | + for (pair<int, ll> i : graph[node]) if (i.first != parent) { |
| 28 | + anc[i.first][0] = node; |
| 29 | + to_anc[i.first][0] = i.second; |
| 30 | + lca_dfs(i.first, node); |
| 31 | + } |
| 32 | + tout[node] = timer++; |
| 33 | +} |
| 34 | + |
| 35 | +inline bool is_ancestor(int u, int v) { return (tin[u] <= tin[v] && tout[u] >= tout[v]); } |
| 36 | + |
| 37 | +int lca(int u, int v) { |
| 38 | + if (is_ancestor(u, v)) return u; |
| 39 | + for (int i = 18; ~i; i--) if (!is_ancestor(anc[u][i], v)) u = anc[u][i]; |
| 40 | + return anc[u][0]; |
| 41 | +} |
| 42 | + |
| 43 | +ll dist(int u, int v) { |
| 44 | + ll ans = 0; |
| 45 | + for (int i = 18; ~i; i--) if (!is_ancestor(anc[u][i], v)) { |
| 46 | + ans += to_anc[u][i]; |
| 47 | + u = anc[u][i]; |
| 48 | + } |
| 49 | + if (!is_ancestor(u, v)) ans += to_anc[u][0]; |
| 50 | + for (int i = 18; ~i; i--) if (!is_ancestor(anc[v][i], u)) { |
| 51 | + ans += to_anc[v][i]; |
| 52 | + v = anc[v][i]; |
| 53 | + } |
| 54 | + if (!is_ancestor(v, u)) ans += to_anc[v][0]; |
| 55 | + return ans; |
| 56 | +} |
| 57 | + |
| 58 | +void Init(int N, int A[], int B[], int D[]) { |
| 59 | + for (int i = 0; i < N - 1; i++) { |
| 60 | + graph[A[i]].push_back({B[i], D[i]}); |
| 61 | + graph[B[i]].push_back({A[i], D[i]}); |
| 62 | + } |
| 63 | + lca_dfs(); |
| 64 | + memset(to_X, 0x3f, sizeof to_X); memset(to_Y, 0x3f, sizeof to_Y); |
| 65 | +} |
| 66 | + |
| 67 | +bool cmp(int u, int v) { return tin[u] < tin[v]; } |
| 68 | + |
| 69 | +ll ans; |
| 70 | + |
| 71 | +void dfs1(int node, int parent = 0) { |
| 72 | + for (pair<int, ll> i : vtree[node]) if (i.first != parent) { |
| 73 | + dfs1(i.first, node); |
| 74 | + to_X[node] = min(to_X[node], to_X[i.first] + i.second); |
| 75 | + to_Y[node] = min(to_Y[node], to_Y[i.first] + i.second); |
| 76 | + } |
| 77 | +} |
| 78 | + |
| 79 | +void dfs2(int node, int parent = 0, ll par_to_X = INF, ll par_to_Y = INF) { |
| 80 | + to_X[node] = min(to_X[node], par_to_X); |
| 81 | + to_Y[node] = min(to_Y[node], par_to_Y); |
| 82 | + ans = min(ans, to_X[node] + to_Y[node]); |
| 83 | + for (pair<int, ll> i : vtree[node]) if (i.first != parent) { |
| 84 | + ll nxt_par_to_X = i.second + min(par_to_X, to_X[node]); |
| 85 | + ll nxt_par_to_Y = i.second + min(par_to_Y, to_Y[node]); |
| 86 | + dfs2(i.first, node, nxt_par_to_X, nxt_par_to_Y); |
| 87 | + } |
| 88 | +} |
| 89 | + |
| 90 | +ll Query(int S, int X[], int T, int Y[]) { |
| 91 | + vector<int> nodes; |
| 92 | + for (int i = 0; i < S; i++) { |
| 93 | + to_X[X[i]] = 0; |
| 94 | + nodes.push_back(X[i]); |
| 95 | + } |
| 96 | + for (int i = 0; i < T; i++) { |
| 97 | + to_Y[Y[i]] = 0; |
| 98 | + nodes.push_back(Y[i]); |
| 99 | + } |
| 100 | + sort(nodes.begin(), nodes.end(), cmp); |
| 101 | + for (int i = 1; i < S + T; i++) nodes.push_back(lca(nodes[i - 1], nodes[i])); |
| 102 | + sort(nodes.begin(), nodes.end(), cmp); |
| 103 | + nodes.erase(unique(nodes.begin(), nodes.end()), nodes.end()); |
| 104 | + vector<int> stck; |
| 105 | + for (int i : nodes) { |
| 106 | + while (stck.size() > 1 && !is_ancestor(stck.back(), i)) { |
| 107 | + int u = stck[stck.size() - 2], v = stck.back(); |
| 108 | + vtree[u].push_back({v, dist(u, v)}); |
| 109 | + stck.pop_back(); |
| 110 | + } |
| 111 | + stck.push_back(i); |
| 112 | + } |
| 113 | + while (stck.size() > 1) { |
| 114 | + int u = stck[stck.size() - 2], v = stck.back(); |
| 115 | + vtree[u].push_back({v, dist(u, v)}); |
| 116 | + stck.pop_back(); |
| 117 | + } |
| 118 | + ans = LLONG_MAX; |
| 119 | + dfs1(stck[0]); |
| 120 | + dfs2(stck[0]); |
| 121 | + for (int i : nodes) { |
| 122 | + to_X[i] = to_Y[i] = INF; |
| 123 | + vtree[i].clear(); |
| 124 | + } |
| 125 | + return ans; |
| 126 | +} |
0 commit comments