传送门(洛谷)
树上倍增+最大生成树
跑一边
K
r
u
s
a
l
Krusal
Krusal求得最大生成树。
树上倍增的时候顺带维护出
g
[
u
]
[
i
]
,
g
[
u
]
[
i
]
表
示
u
向
上
跳
2
i
步
的
路
径
中
的
最
小
值
g[u][i],g[u][i]表示u向上跳2^i步的路径中的最小值
g[u][i],g[u][i]表示u向上跳2i步的路径中的最小值
注意一个细节问题,在 d f s dfs dfs时候注意可能不是一棵树而是几棵树,所以我们对重构树的每个已经遍历过的点打上标记,再遍历没有遍历过的点
接下来常规操作
rep(i,0,19) {
f[u][i+1]=f[f[u][i]][i];;//求倍增
g[u][i+1]=min(g[u][i],g[f[u][i]][i]);//求这条链上的最小值
}
Code
#include<bits/stdc++.h>
#define rep(i,a,b) for(register int (i)=(a);(i)<=(b);(i)++)
#define don(i,a,b) for(register int (i)=(a);(i)>=(b);(i)--)
using namespace std;
const int maxn=1e5+10;
const int maxm=1e3+10;
int n,m,q,minn,cnt;
int dep[maxn],head[maxn],f[maxn][21],fa[maxn],vis[maxn],g[maxn][21];
struct {
int v,nex,w;
}e[maxn<<1];
struct node{
int u,v,w;
friend bool operator < (const node &A,const node &B) {
return A.w>B.w;
}
}a[maxn];
template <class t> inline void read(t &x)
{
x=0;int f=1;char ch=getchar();
while(!isdigit(ch)){if(ch=='-') f=-1;ch=getchar();}
while(isdigit(ch)){x=10*x+ch-'0';ch=getchar();}
x*=f;
}
void add(int u,int v,int w) {
e[++cnt].v=v;
e[cnt].w=w;
e[cnt].nex=head[u];
head[u]=cnt;
}
inline int find(int x) {
if(fa[x]==x) return x;
else return fa[x]=find(fa[x]);
}
void Krusal() {
int k=0;
rep(i,0,n+1) fa[i]=i;
rep(i,1,m) {
if(k==n-1) break;
int f1=find(a[i].u);
int f2=find(a[i].v);
if(f1==f2) continue;
k++;
fa[f1]=f2;
add(a[i].u,a[i].v,a[i].w);
add(a[i].v,a[i].u,a[i].w);
}
}
void readdata() {
memset(g,0x7f,sizeof(g));
read(n),read(m);
rep(i,1,m) {
read(a[i].u);read(a[i].v);
read(a[i].w);
}
sort(a+1,a+1+m);
Krusal();
}
void dfs(int u,int fa) {
vis[u]=true;
dep[u]=dep[fa]+1;
f[u][0]=fa;
rep(i,0,19) {
f[u][i+1]=f[f[u][i]][i];;
g[u][i+1]=min(g[u][i],g[f[u][i]][i]);
}
for(int i=head[u];i;i=e[i].nex) {
int v=e[i].v;
if(v==fa) continue;
g[v][0]=e[i].w;
dfs(v,u);
}
}
inline int LCA(int x,int y) {
if(dep[x]<dep[y]) swap(x,y);
don(i,20,0) {
if(dep[f[x][i]]>=dep[y]) {
minn=min(minn,g[x][i]);
x=f[x][i];
}
if(x==y) return minn;
}
don(i,20,0) {
if(f[x][i]!=f[y][i]) {
minn=min(minn,min(g[x][i],g[y][i]));
x=f[x][i];
y=f[y][i];
}
}
minn=min(minn,min(g[x][0],g[y][0]));
return minn;
}
void work() {
read(q);
rep(i,1,n) {//此地注意遍历每一棵树
if(!vis[i])
dfs(i,0);
}
rep(i,1,q) {
int x,y;
read(x),read(y);
minn=INT_MAX;
if(find(x)!=find(y)) printf("-1\n");
else printf("%d\n",LCA(x,y));
}
}
int main() {
//freopen("input.txt","r",stdin);
readdata();
work();
return 0;
}