2019 UESTC ACM Training for Data Structures[B]

问题描述:给一棵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)的权值的相反数即为所求的答案。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值