UVA - 11354Bond最小生成树,LCA寻找最近公共祖先

/*
Author: 2486
Memory: 0 KB		Time: 2222 MS
Language: C++11 4.8.2		Result: Accepted
VJ RunId: 4236841		Real RunId: 15859210
*/
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <queue>
#include <vector>
using namespace std;
const int maxn=50000+5;
const int maxm=100000+5;
int N,M,m;
int par[maxn],dist[maxn],depth[maxn],vis[maxn];
struct edge {
    int u,v,cost;
    bool operator<(const edge &a)const {
        return cost<a.cost;
    }
} es[maxm];
struct ed {
    int to,cost;
    ed(int to,int cost):to(to),cost(cost) {}
};
vector<ed>G[maxn];
void init(int c) {
    for(int i=0; i<maxn; i++) {
        par[i]=i;
        dist[i]=-1;
        if(c)G[i].clear();
    }
    memset(vis,false,sizeof(vis));
}
int find(int x) {
    return par[x]==x?x:par[x]=find(par[x]);
}
bool same(int x,int y) {
    return find(x)==find(y);
}
void unite(int x,int y) {
    x=find(x);
    y=find(y);
    par[x]=y;
}
int lca(int a, int b) { //a的深度<=b的深度
    int m1 = -1;
    while(depth[a] < depth[b]) { //将深度调到一样
        m1 = max(m1, dist[b]);
        b = par[b];
    }
    while(a != b) {//同时从节点走到祖先节点
        m1 = max(m1, dist[a]);
        m1 = max(m1, dist[b]);
        a = par[a], b = par[b];
    }
    return m1;
}
void kj() {
    sort(es,es+M);
    init(1);
    int cnt=0;
    /**********将组成最小生成树的边全都保存起来*************/
    /**********大家都懂,这是Kruskal算法*************/
    for(int i=0; i<M; i++) {
        edge e=es[i];
        if(!same(e.v,e.u)) {
            unite(e.v,e.u);
            G[e.v].push_back(ed(e.u,e.cost));
            G[e.u].push_back(ed(e.v,e.cost));
        }
    }
    /***********************/
    dist[1]=0;
    depth[1]=0;
    queue<int>F;
    F.push(1);
    vis[1]=true;
    init(0);
    /*********这个是很重要的**************/
    /*********以1号城市为根节点,然后就是开始遍历形成一棵树**************/
    /***********大家可以想象一下,如果城市在一棵树的某个节点上************/
    /***********那么什么才是从一个点到另一个点的路径呢?************/
    /***********很简单,将他们从他们自己的节点向上递推到两个点的共同祖先就可以了************/
    /***********中间经历的就是从一个点到另一个点的路径************/
    /***********如此,就直接用队列处理一下即可************/
    while(!F.empty()) {
        int v=F.front();
        F.pop();
        for(int i=0; i<G[v].size(); i++) {
            ed e=G[v][i];
            if(vis[e.to])continue;
            vis[e.to]=true;
            par[e.to]=v;//他的父亲节点
            depth[e.to]=depth[v]+1;//他的深度
            dist[e.to]=e.cost;//从该节点到父亲节点的危险度
            F.push(e.to);
        }
    }
    /***********************/
}

int main() {
    int cases=1;
//freopen("D://imput.txt","r",stdin);
    while(~scanf("%d%d",&N,&M)) {
        for(int i=0; i<M; i++) {
            scanf("%d%d%d",&es[i].u,&es[i].v,&es[i].cost);
        }
        if(cases!=1)printf("\n");//注意题目格式,需要换行
        kj();
        int s,t;
        scanf("%d",&m);
        while(m--) {
            scanf("%d%d",&s,&t);//读取命令
            if(depth[s]>depth[t])swap(s,t);
            printf("%d\n",lca(s,t));
        }
        cases++;
    }
    return 0;
}

版权声明:本文为博主原创文章,未经博主允许不得转载。

时间: 2024-11-08 17:03:26

UVA - 11354Bond最小生成树,LCA寻找最近公共祖先的相关文章

LCA(最近公共祖先)——离线 Tarjan 算法

一.梳理概念 定义:对于有根树T的两个结点u.v,最近公共祖先LCA(T,u,v)表示一个结点x,满足x是u.v的祖先且x的深度尽可能大. 通俗地讲,最近公共祖先节点,就是两个节点在这棵树上深度最大的公共的祖先节点,即两个点在这棵树上距离最近的公共祖先节点. 提示:父亲节点也是祖先节点,节点本身也是它的祖先节点. 给出一棵树,如图所示: 由上面的定义可知:3和5的最近公共祖先为1,5和6的最近公共祖先为2,2和7的最近公共祖先为2, 6和7的最近公共祖先为4. 二.繁文缛节 注意注意注意!!!尚

【LCA求最近公共祖先+vector构图】Distance Queries

Distance Queries 时间限制: 1 Sec  内存限制: 128 MB 题目描述 约翰的奶牛们拒绝跑他的马拉松,因为她们悠闲的生活不能承受他选择的长长的赛道.因此他决心找一条更合理的赛道.此题的输入于第一题相同,紧接着下一行输入一个整数K,以后K行为K个"距离问题".每个距离问题包括两个整数,就是约翰感兴趣的两个农场的编号,请你尽快算出这两地之间的距离. N个点,N-1条边 输入 第1行:两个分开的整数:N和M: 第2..M+1行:每行包括4个分开的内容,F1,F2,L,

LCA(最近公共祖先)--tarjan离线算法 hdu 2586

HDU 2586 How far away ? Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 11320    Accepted Submission(s): 4119 Problem Description There are n houses in the village and some bidirectional roads c

算法模板——LCA(最近公共祖先)

实现的功能如下——在一个N个点的无环图中,共有N-1条边,M个访问中每次询问两个点的距离 原理——既然N个点,N-1条边,则说明这是一棵树,而且联通.所以以1为根节点DFS建树,然后通过求两点的LCA的方式,先求得最近公共祖先,然后再通过深度来求出两点距离 1 type 2 point=^node; 3 node=record 4 g:longint; 5 next:point; 6 end; 7 const 8 maxn=100500; 9 maxm=trunc(ln(maxn)/ln(2))

[图论] LCA(最近公共祖先)Tarjan 离线算法

很好的参考资料:http://taop.marchtea.com/04.04.html    下面的配图和部分文字转载于此文章 离线算法就是指统一输入后再统一输出,而不是边输入边实时输出.Tarjan算法的复杂度为O(N+Q),Q为询问的次数. 由于是离线算法,所以要保存输入的信息,次序问题. 若两个结点u.v分别分布于某节点t 的左右子树,那么此节点 t即为u和v的最近公共祖先.更进一步,考虑到一个节点自己就是LCA的情况,得知: ?若某结点t 是两结点u.v的祖先之一,且这两结点并不分布于该

HDU 2586 How far away ?(LCA模板 近期公共祖先啊)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2586 Problem Description There are n houses in the village and some bidirectional roads connecting them. Every day peole always like to ask like this "How far is it if I want to go from house A to house

HDU 2586 How far away ?(LCA模板 最近公共祖先啊)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2586 Problem Description There are n houses in the village and some bidirectional roads connecting them. Every day peole always like to ask like this "How far is it if I want to go from house A to house

LCA(最近公共祖先)算法

参考博客:https://blog.csdn.net/my_sunshine26/article/details/72717112 首先看一下定义,来自于百度百科 LCA(Lowest Common Ancestors),即最近公共祖先,是指在有根树中,找出某两个结点u和v最近的公共祖先. 注意:这里某个节点本身也是它的祖先节点. 求最近公共祖先的算法: 1.暴力:每次查询的时间复杂度为O(N) 2.Tarjan(离线)算法:在一次遍历中把所有查询解决,预处理时间复杂度O(nlogn),每次查询

lca(最近公共祖先(在线)) 倍增法详解

转自大佬博客 : https://blog.csdn.net/lw277232240/article/details/72870644 描述:倍增法用于很多算法当中,通过字面意思来理解 LCA是啥呢  在一棵树当中 lca表示的是两个节点最近公共祖先, 大家看这课树哈节点5 ,3的lca就是1,13和11的LCA就是6.节点8,12的lca就是8,那么我们如何通过被增来实现LCA呢. 首先请大家认真看下面的分析. depth[x],表示x节点的深度. 大家看下这个数组 grand[x][i] ,