zoukankan      html  css  js  c++  java
  • 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
    ",v[ask(read(),read())]);
    }
    
    int main(){
    	init();
    	kruskal();
    	division();
    	solve();
    	return 0;
    }
    

    NOIP2013货车运输也是一道这样的题

  • 相关阅读:
    [黑防VIP课程]汇编基础一日一学习2
    立即释放.net下的com组件
    WinExec,ShellExecute ,CreateProcess 区别
    .Net中如何操作IIS(原理篇)+实现类
    全用存储过程和全用SQL思考笔记
    C# 中的常用正则表达式总结
    .Net中窗体间传递值的一种方法
    [黑防VIP课程]汇编基础一日一学习1
    [黑防VIP课程]汇编基础一日一学习2
    浮点指令
  • 原文地址:https://www.cnblogs.com/Mychael/p/8282874.html
Copyright © 2011-2022 走看看