Editorial for Hoptiver
Remember to use this editorial only when stuck, and not to copy-paste code from it. Please be respectful to the problem author and editorialist.
Submitting an official solution before solving the problem yourself is a bannable offence.
Submitting an official solution before solving the problem yourself is a bannable offence.
Approach
The connections form a tree on nodes. The profit along the unique path between
and
is the sum of edge weights on that path.
Root the tree at node and compute the distance
from the root to every node
(the sum of edge weights along that path). For any query
:
.
Compute LCAs with binary lifting in per query after
preprocessing.
Overall time is
.
Solution (C++)
#include <bits/stdc++.h>
using namespace std;
vector<vector<pair<int, int> > > adj;
vector<int> tin, tout, dist;
vector<vector<int> > up;
int timer_dfs = 0;
int LOGN;
void dfs(int v, int p, int d) {
tin[v] = ++timer_dfs;
dist[v] = d;
up[v][0] = p;
for (int i = 1; i < LOGN; i++) {
up[v][i] = up[up[v][i - 1]][i - 1];
}
for (size_t j = 0; j < adj[v].size(); j++) {
int to = adj[v][j].first;
int w = adj[v][j].second;
if (to != p) {
dfs(to, v, d + w);
}
}
tout[v] = ++timer_dfs;
}
bool is_ancestor(int a, int b) {
return tin[a] <= tin[b] && tout[a] >= tout[b];
}
int lca(int a, int b) {
if (is_ancestor(a, b)) {
return a;
}
if (is_ancestor(b, a)) {
return b;
}
for (int i = LOGN - 1; i >= 0; i--) {
if (!is_ancestor(up[a][i], b)) {
a = up[a][i];
}
}
return up[a][0];
}
int main() {
ios::sync_with_stdio(false);
cin.tie(0);
int n, q;
cin >> n >> q;
adj.assign(n, vector<pair<int, int> >());
tin.assign(n, 0);
tout.assign(n, 0);
dist.assign(n, 0);
LOGN = 1;
while ((1 << LOGN) <= n) {
LOGN++;
}
up.assign(n, vector<int>(LOGN));
for (int i = 0; i < n - 1; i++) {
int a, b, c;
cin >> a >> b >> c;
adj[a].push_back(make_pair(b, c));
adj[b].push_back(make_pair(a, c));
}
dfs(0, 0, 0);
for (int i = 0; i < q; i++) {
int a, b;
cin >> a >> b;
int ancestor = lca(a, b);
cout << dist[a] + dist[b] - 2 * dist[ancestor] << "\n";
}
}
Comments