zoukankan      html  css  js  c++  java
  • 货车运输(倍增 LCA 生成树)

    传送门

    前置知识:LCA 倍增 生成树

    如果单纯求出从 1 号点到** n **号点的最小且最大的那条路,只需要灵活跑一遍
    最短路就可以了

    然而对于求任意两点之间的距离,上述方法就时间复杂度过大无法通过。考虑
    到降低复杂度,此时选择使用倍增的方法,是的原本O(n)的时间复杂度降低为
    logn

    此时问题就在于如何使用倍增方法求解距离,借助求LCA的方法,可以得知求距离
    的方法和求LCA的方法是一样的,因此距离也就能够求出来了

    #include <bits/stdc++.h>
    using namespace std;
    
    const int N = 1e4 + 10;
    
    int father[N], n, m, tot, head[N], dep[N], fa[N][22], value[N][22];
    bool vis[N];
    struct Edge{
    	int u, v, next, w;
    }edge[N << 3], edge1[N << 3];
    
    
    void add(int u, int v, int w){
    	edge[tot].v = v;
    	edge[tot].w = w;
    	edge[tot].next = head[u];
    	head[u] = tot ++;
    }
    
    int find(int x){
    	if(x == father[x])
    		return x;
    	else
    		return father[x] = find(father[x]);
    }
    bool cmp(Edge a, Edge b){
    	return a.w > b.w;
    }
    void kruskal(){
    	sort(edge1 + 1, edge1 + 1 + m, cmp);
    	int cnt = 0;
    	for(int i = 1; i <= m; i ++){
    		int a = edge1[i].u;
    		int b = edge1[i].v;
    		int aa = find(a), bb = find(b);
    		if(aa == bb)
    			continue;
    		father[aa] = bb;
    		cnt ++;
    		add(a, b, edge1[i].w);
    		add(b, a, edge1[i].w);
    		if(cnt == n)
    			return;
    	}
    }
    void dfs(int now, int pre, int w){
    	vis[now] = true;
    	dep[now] = dep[pre] + 1;
    	fa[now][0] = pre;
    	value[now][0] = w;
    	for(int i = head[now]; i != -1; i = edge[i].next){
    		int v = edge[i].v;
    		if(v != pre){
    			dfs(v, now, edge[i].w);
    		}
    	}
    }
    int getlca(int u, int v){
    	if(find(u) != find(v)){
    		return -1;
    	}
    	if(dep[u] < dep[v])
    		swap(u, v);
    	int ans = 0x3f3f3f3f;
    	while(dep[u] > dep[v]){
    		ans = min(ans, value[u][(int)log2(dep[u] - dep[v])]);
    		u = fa[u][(int)log2(dep[u] - dep[v])];
    	}
    	if(u == v)
    		return ans;
    	for(int i = 20; i >= 0; i --){
    		if(fa[u][i] != fa[v][i]){
    			ans = min(ans, value[u][i]);
    			ans = min(ans, value[v][i]);
    			u = fa[u][i];
    			v = fa[v][i];
    		}
    	}
    	ans = min(ans, min(value[u][0], value[v][0]));
    	return ans;
    }
    int main(){
    	cin >> n >> m;
    	for(int i = 1; i <= n; i ++)
    		father[i] = i;
    	memset(head, -1, sizeof head);
    	for(int i = 1; i <= m; i ++){
    		int u, v, w;
    		cin >> u >> v >> w;
    		edge1[i].u = u;
    		edge1[i].v = v;
    		edge1[i].w = w;
    	}
    	kruskal();
    	
    	
    	for(int i = 1; i <= n; i ++){
    		if(!vis[i]){
    			dfs(i, 0, 0);
    		}
    	}
    	for(int j = 1; j <= 20; j ++){
    		for(int i = 1; i <= n; i ++){
    			fa[i][j] = fa[fa[i][j - 1]][j - 1];
    			value[i][j] = min(value[i][j - 1], value[fa[i][j - 1]][j - 1]);
    		}
    	}
    	int q;
    	cin >> q;
    	while(q --){
    		int a, b;
    		cin >> a >> b;
    		cout << getlca(a, b) << endl;
    	}
    	
    	return 0;
    }
    
  • 相关阅读:
    git 的学习使用记录
    Servlet发送邮件遇到的问题SMTPSendFailedException 554
    如何高效地写CSS--等以后有空多加总结一下
    前端技术科技树梳理
    React了解
    读取Excel文件
    Eclipse不能自动编译 java文件
    破天荒地敲下第一篇
    SRM DIV2 569 TheDeviceDiv2
    SRM DIV2 570 RobotHerbDiv2
  • 原文地址:https://www.cnblogs.com/pureayu/p/15171772.html
Copyright © 2011-2022 走看看