Kruskal重构树是基于Kruskal算法的,典型的应用是求两点之间边权最大值的最小值。
首先,我们运行Kruskal算法,将边从小到大排列,在运行过程中,每加入一条边,就建立一个节点u,权值为边权的权值w,然后所连两点a,b所在子树的根节点作为它的儿子,就像这样:
由于边是按升序加入的,所以这棵二叉树为大根堆,如果需要求两点之间在生成树中路径上最大权值,那么求两点LCA就好了
BZOJ3732
板题
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define LL long long int
using namespace std;
const int maxn=30005,maxv=100005,maxm=100005,INF=2000000000,P=1000000007;
inline int read(){
int out=0,flag=1;char c=getchar();
while(c<48||c>57) {if(c=='-') flag=-1;c=getchar();}
while(c>=48&&c<=57){out=out*10+c-48;c=getchar();}
return out*flag;
}
int N,M,K;
struct EE{
int a,b,w;
}Edge[maxm];
inline bool operator <(const EE& a,const EE& b){
return a.w<b.w;
}
int head[maxv],nedge = 0;
struct EDGE{
int to,next;
}edge[maxm];
inline void build(int a,int b){
edge[nedge] = (EDGE){b,head[a]};
head[a] = nedge++;
edge[nedge] = (EDGE){a,head[b]};
head[b] = nedge++;
}
void init(){
fill(head,head+maxv,-1);
N = read();
M = read();
K = read();
for(int i=1; i<=M; i++){
Edge[i].a = read();
Edge[i].b = read();
Edge[i].w = read();
}
}
int nodei=0,pre[maxv],v[maxn];
inline int find(int x){return x == pre[x] ? x : pre[x]=find(pre[x]);}
void kruskal(){
sort(Edge+1,Edge+1+M);
for (int i = 1; i <= N; i++) pre[i]=i;
nodei=N;
int fa,fb;
for (int i = 1; i <= M; i++){
fa = find(Edge[i].a);
fb = find(Edge[i].b);
if (fa != fb){
v[++nodei] = Edge[i].w;
pre[fa] = pre[fb] = pre[nodei] = nodei;
build(fa,nodei);
build(fb,nodei);
}
}
}
bool vis[maxv];
int top[maxv],son[maxv],fa[maxv],siz[maxv],dep[maxv];
void dfs1(int u,int f,int d){
fa[u] = f;dep[u] = ++d;siz[u] = 1;vis[u] = true;
int to;
for (int k = head[u]; k != -1; k = edge[k].next)
if ((to = edge[k].to) != f){
dfs1(to,u,d);
siz[u] += siz[to];
if (!son[u]||siz[to] > siz[son[u]]) son[u] = to;
}
}
void dfs2(int u,int flag){
top[u] = flag ? top[fa[u]] : u;
int to;
if (son[u]) dfs2(son[u],true);
for (int k = head[u]; k != -1; k = edge[k].next)
if ((to = edge[k].to) != son[u]&&to != fa[u])
dfs2(to,false);
}
void division(){
for (int i = 1; i <= nodei; i++)
if (!vis[i]){
dfs1(find(i),0,0);
dfs2(find(i),0);
}
}
int ask(int u,int v){
while (top[u] != top[v])
dep[top[u]] > dep[top[v]] ? u = fa[top[u]] : v = fa[top[v]];
return dep[u] > dep[v] ? v:u;
}
void solve(){
while (K--) printf("%d\n",v[ask(read(),read())]);
}
int main(){
init();
kruskal();
division();
solve();
return 0;
}
NOIP2013货车运输也是一道这样的题