给一棵n个点的树,每条边上有边权。
给q个询问u,v,每次询问路径u,v上的最小值。
输入格式
第一行两个整数n,q(1≤n,q≤2×105)。
接下来n−1行,每行两个整数u,v,w(1≤w≤109)表示一条边的两个端点和边权。
接下来q行,每行两个整数u,v(u≠v,1≤u,v≤n)表示询问的两个端点。
输出格式
对于每组询问,输出一个数表示答案。
样例输入
5 5
1 2 3
2 3 4
2 4 5
3 5 2
4 5
1 3
2 4
1 5
1 4
样例输出
2
3
5
2
3
思路:用倍增的思想,从2的0次方,2的一次方,2的2次方......依次记录下来在进行比较
代码
#include <bits/stdc++.h>
using namespace std;
#define int long long
const int N = 2e5 + 10,LOGN = 30;
vector<pair<int,int>>e[N];
int n,q;
int dep[N],p[N][LOGN+1],val[N][LOGN + 1];
void dfs(int u,int f)
{
dep[u] = dep[f] + 1;
//cout << u << ' ' << f << '\n';
for(auto [x,y]:e[u])
{
if(x == f)
continue;
p[x][0] = u;
val[x][0] = y;
dfs(x,u);
}
}
int query(int u,int v)
{
int ans = 1<<30;
if(dep[u] > dep[v])
swap(u,v);
int d = dep[v] - dep[u];
for(int j = LOGN;j >= 0;j --)
if(d&(1<<j))
{
ans = min(ans,val[v][j]);
v = p[v][j];
}
if(u == v)
return ans;
for(int j = LOGN;j >= 0;j --)
if(p[u][j]!=p[v][j])
{
ans = min(ans,min(val[u][j],val[v][j]));
u = p[u][j];
v = p[v][j];
}
ans = min(ans,min(val[u][0],val[v][0]));
return ans;
}
void solve()
{
cin >> n >> q;
for(int i = 1;i < n;i ++)
{
int u,v,w;
cin >> u >> v >> w;
e[u].push_back({v,w});
e[v].push_back({u,w});
}
// for(int i = 1;i <= n;i ++)
// {
// for(int j = 0;j < e[i].size();j ++)
// cout << e[i][j].first <<' ';
// cout << '\n';
// }
dfs(1,0);
for(int j = 1;j <= LOGN; j ++)
{
for(int u = 1;u <= n;u ++)
{
p[u][j] = p[p[u][j-1]][j-1];
//cout << p[u][j] << ' ' << u << ' ' << j << ' ' <<p[u][j-1]<<'\n';
val[u][j] = min(val[u][j-1],val[p[u][j-1]][j-1]);
}
}
// for(int i = 1;i <= n;i ++)
// {
// for(int j = 1;j <= 18;j ++)
// cout << p[i][j] << ' ' << i << ' ' << j << '\n';
// }
for(int i = 1;i <= q;i ++)
{
int u,v;
cin >> u >> v;
cout << query(u,v) << '\n';
}
}
signed main()
{
solve();
}