版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/getsum/article/details/91042174
问题描述:给一棵n个节点的树,给出q次询问,每次询问u,v节点的路径上的边权最小值。
先将输入的边变负存入,然后按从小到大排序(对应到原边是从大到小)。
然后依次枚举每一条边,每一条边的端点判断是否在同一集合中,如果不在,则通过并查集合并。
注意合并时要创建新的节点,将这两个端点接入这个新的节点中。
然后用val数组表示每个节点的“权值”。对于新创建的节点,将权值赋成合并时两个端点的边权。
这样,我们新建的树的叶子节点就全都是原先的
#include<iostream>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#include<queue>
#include<stack>
#include<vector>
#include<cmath>
#define LL long long
using namespace std;
const int inf=0x3f3f3f3f;
const int maxn=2e5+5;
const int maxs=19;
struct Edge{
int from,to,d;
Edge(int from,int to,int d):from(from),to(to),d(d){};
bool operator <(const Edge &h)const{
return d<h.d;
}
};
vector<int>G[2*maxn];
vector<Edge>edges;
vector<Edge>tedges;
int n,q,dis[maxn],fat[maxn],val[maxn],cur,fa[maxn][20];
int depth[maxn];
void add_edges(int from,int to,int d){
d=-d;
edges.push_back(Edge(from,to,d));
G[from].push_back(edges.size()-1);
edges.push_back(Edge(to,from,d));
G[to].push_back(edges.size()-1);
}
int getfa(int x){return fat[x]==x?x:fat[x]=getfa(fat[x]);}
void build_tree(){//并查集合并,建立新树
cur=n;
for(int i=1;i<=2*n;i++)fat[i]=i;
for(int i=0;i<tedges.size();i++){
Edge e=tedges[i];
int u=e.from,v=e.to;
//cout<<u<<" "<<v<<" "<<getfa(u)<<" "<<getfa(v)<<" "<<cur+1<<"~~~~~~~~~~~~~~~~~~~~"<<endl;
if(getfa(u)!=getfa(v)){
cur++;
val[cur]=e.d;
add_edges(getfa(u),cur,1);
add_edges(getfa(v),cur,1);
fat[fat[u]]=fat[fat[v]]=cur;
}
}
}
void dfs(int u,int f){
int i,j,k;
fa[u][0]=f;
depth[u]=depth[fa[u][0]]+1;
k=ceil(log(depth[u])/log(2));
for(i=1;i<=k;i++)fa[u][i]=fa[fa[u][i-1]][i-1];
for(int i=0;i<G[u].size();i++){
Edge e=edges[G[u][i]];
if(e.to==f)continue;
dfs(e.to,u);
}
}
int lca(int x,int y){
int i,k,s;
s=ceil(log(n*2)/log(2));
if(depth[x]<depth[y])swap(x,y);
k=depth[x]-depth[y];
for(i=0;i<=s;i++)
if(k&(1<<i))x=fa[x][i];
if(x==y)return x;
s=ceil(log(depth[x])/log(2));
for(i=s;i>=0;i--)
if(fa[x][i]!=fa[y][i]){ x=fa[x][i]; y=fa[y][i]; }
return fa[x][0];
}
int main(){
scanf("%d%d",&n,&q);
int x,y,z;
for(int i=1;i<n;i++){
scanf("%d%d%d",&x,&y,&z);
tedges.push_back(Edge(x,y,-z));//存负边
}
sort(tedges.begin(),tedges.end());
build_tree();
dfs(cur,0);
while(q--){
scanf("%d%d",&x,&y);
int gf=lca(x,y);
printf("%d\n",-val[gf]);
}
}
树的节点,对于询问的两点u,v LCA(u,v)的权值的相反数即为所求的答案。