倍增法(在线)
预处理O(nlogn),每次查询O(logn)
int h[N], e[M], ne[M], w[M], idx; //memset(h, -1, sizeof h);
int depth[N], fa[N][21];
int dist[N];
void add(int a, int b, int c) //添加一条由a指向b的边,权重为c
{
w[idx] = c;
e[idx] = b;
ne[idx] = h[a];
h[a] = idx++;
}
void bfs(int root)
{
depth[root] = 1;
queue<int> q;
q.push(root);
while (q.size())
{
int u = q.front();
q.pop();
for (int i = h[u]; ~i; i = ne[i])
{
int v = e[i];
if (depth[v])
{
continue;
}
depth[v] = depth[u] + 1;
dist[v] = dist[u] + w[i];
q.push(v);
fa[v][0] = u;
for (int k = 1; k <= 20; k++)
{
fa[v][k] = fa[fa[v][k - 1]][k - 1];
}
}
}
}
int lca(int a, int b)//返回a,b的最近公共祖先
{
if (depth[a] < depth[b])
{
swap(a, b);
}
for (int k = 20; k >= 0; k--)
{
if (depth[fa[a][k]] >= depth[b])
{
a = fa[a][k];
}
}
if (a == b)
{
return a;
}
for (int k = 20; k >= 0; k--)
{
if (fa[a][k] != fa[b][k])
{
a = fa[a][k];
b = fa[b][k];
}
}
return fa[a][0];
}
Tarjan(离线)
O(n+m)
int h[N], e[M], ne[M], w[M], idx; //memset(h, -1, sizeof h);
int dist[N];
int p[N];
int res[M];
int st[N];
vector<PII> query[N]; // first存查询的另外一个点,second存查询编号
void add(int a, int b, int c) //添加一条由a指向b的边,权重为c
{
w[idx] = c;
e[idx] = b;
ne[idx] = h[a];
h[a] = idx++;
}
void dfs(int u, int father)
{
for (int i = h[u]; ~i; i = ne[i])
{
int v = e[i];
if (v == father)
{
continue;
}
dist[v] = dist[u] + w[i];
dfs(v, u);
}
}
int find(int x) //返回x的祖宗节点
{
return x == p[x] ? x : p[x] = find(p[x]);
}
void tarjan(int u)
{
st[u] = 1;
for (int i = h[u]; ~i; i = ne[i])
{
int v = e[i];
if (!st[v])
{
tarjan(v);
p[v] = u;
}
}
for (auto item : query[u])
{
int y = item.first, id = item.second;
if (st[y] == 2)
{
int anc = find(y);
res[id] = dist[u] + dist[y] - 2 * dist[anc];
}
st[u] = 2;
}
}
int main()
{
std::ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
memset(h, -1, sizeof h);
cin >> n >> m;
for (int i = 1; i < n; i++)
{
int a, b, c;
cin >> a >> b >> c;
add(a, b, c), add(b, a, c);
}
for (int i = 0; i < m; i++) //存储提问
{
int a, b;
cin >> a >> b;
if (a != b)
{
query[a].push_back({b, i});
query[b].push_back({a, i});
}
}
for (int i = 1; i <= n; i++) //初始化并查集
{
p[i] = i;
}
dfs(1, -1); //初始化
tarjan(1);
for (int i = 0; i < m; i++) //输出结果
{
cout << res[i] << endl;
}
return 0;
}