「NOIP2013」货车运输

传送门
Luogu

解题思路

首先 \(\text{Kruskal}\) 一下,构造出一棵森林。
并查集还要用来判断连通性。
倍增 \(\text{LCA}\) 的时候顺便维护一下路径最小值即可。

细节注意事项

  • 代码稍微有点长,不要出小问题

参考代码

#include<cstdio>
#include<algorithm>
using std::sort;
const int MAXN=1e4+10;
const int MAXM=5*1e4+10;
inline int min(int a,int b){return a<b?a:b;}
inline void swap(int& a,int& b){int t=a;a=b;b=t;}
inline int read(){
	int s=0;bool f=false;char c=getchar();
	while(c<'0'||c>'9')f|=(c=='-'),c=getchar();
	while(c>='0'&&c<='9')s=(s<<3)+(s<<1)+(c^48),c=getchar();
	return (f)?(-s):(s);
}
int n,m,q;
struct edge{int u,v,w;}g[MAXM];
inline bool cmp(edge a,edge b){return a.w>b.w;}
int tot,ver[MAXM<<1],dis[MAXM<<1],nxt[MAXM<<1],fir[MAXN];
inline void Add_edge(int u,int v,int w){
	nxt[++tot]=fir[u],fir[u]=tot,ver[tot]=v,dis[tot]=w;
	nxt[++tot]=fir[v],fir[v]=tot,ver[tot]=u,dis[tot]=w;
}
int dad[MAXN];
inline int findd(int k){
	return dad[k]==k?k:dad[k]=findd(dad[k]);
}
inline bool is_unionn(int u,int v){
	return findd(u)==findd(v);
}
inline void unionn(int u,int v){
	int fu=findd(u),fv=findd(v);
	if(fu!=fv)dad[fv]=fu;
}
inline void Kruskal(){
	for(int i=1;i<=n;i++)
		dad[i]=i;
	sort(g+1,g+m+1,cmp);
	for(int i=1;i<=m;i++)
		if(!is_unionn(g[i].u,g[i].v))
			unionn(g[i].u,g[i].v),Add_edge(g[i].u,g[i].v,g[i].w);
}
bool vis[MAXN];
int dep[MAXN],f[MAXN][22],w[MAXN][22];
inline void dfs(int u){
	vis[u]=true;
	for(int v,i=fir[u];i;i=nxt[i])
		if(!vis[v=ver[i]])
			dep[v]=dep[u]+1,f[v][0]=u,w[v][0]=dis[i],dfs(v);
}
inline int LCA(int x,int y){
	if(!is_unionn(x,y)) return -1;
	int ans=2147483647;
	if(dep[x]<dep[y])swap(x,y);
	for(int i=20;i>=0;--i)
        if(dep[f[x][i]]>=dep[y])
            ans=min(ans,w[x][i]),x=f[x][i];
	if(x==y) return ans;
	for(int i=20;i>=0;--i)
		if(f[x][i]!=f[y][i])
			ans=min(ans,min(w[x][i],w[y][i])),x=f[x][i],y=f[y][i];
	return min(ans,min(w[x][0],w[y][0]));
}
int main(){
	n=read(),m=read();
	for(int i=1;i<=m;i++)
		g[i].u=read(),g[i].v=read(),g[i].w=read();
	Kruskal();
	for(int i=1;i<=n;i++)
		if(!vis[i]){
			dep[i]=1;
			dfs(i);
			f[i][0]=i;
			w[i][0]=2147483647;
		}
	for(int i=1;i<=20;i++)
        for(int j=1;j<=n;j++)
            f[j][i]=f[f[j][i-1]][i-1],w[j][i]=min(w[j][i-1],w[f[j][i-1]][i-1]);
	q=read();
	for(int x,y,i=1;i<=q;i++)
		x=read(),y=read(),printf("%d\n",LCA(x,y));
	return 0;
}

完结撒花 \(qwq\)

posted @ 2019-10-26 21:56  Sangber  阅读(183)  评论(0编辑  收藏  举报