Kruskal重构树
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货车运输也是一道这样的题