zoukankan      html  css  js  c++  java
  • BZOJ 3732 Network —— 最小生成树 + 倍增LCA

    题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=3732


    Description

    给你N个点的无向图 (1 <= N <= 15,000),记为:1…N。 
    图中有M条边 (1 <= M <= 30,000) ,第j条边的长度为: d_j ( 1 < = d_j < = 1,000,000,000).

    现在有 K个询问 (1 < = K < = 20,000)。 
    每个询问的格式是:A B,表示询问从A点走到B点的所有路径中,最长的边最小值是多少?

    Input

    第一行: N, M, K。 
    第2..M+1行: 三个正整数:X, Y, and D (1 <= X <=N; 1 <= Y <= N). 表示X与Y之间有一条长度为D的边。 
    第M+2..M+K+1行: 每行两个整数A B,表示询问从A点走到B点的所有路径中,最长的边最小值是多少?

    Output

     对每个询问,输出最长的边最小值是多少。

    Sample Input

    6 6 8
    1 2 5
    2 3 4
    3 4 3
    1 4 8
    2 5 7
    4 6 2
    1 2
    1 3
    1 4
    2 3
    2 4
    5 1
    6 2
    6 1

    Sample Output

    5
    5
    5
    4
    4
    7
    4
    5

    HINT

     

    1 <= N <= 15,000 

    1 <= M <= 30,000 

    1 <= d_j <= 1,000,000,000 

    1 <= K <= 15,000




    题解:

    由题目可知,此图为连通图

    所有路径最长边的最小值,即为最小生成树下路径的最长边。因为在最小生成树下,所有边都是最优的,所以保证了最小值。那自然在最小生成树的路径下,最长边即为所求的边。

    步骤:

    1.构造最小生成树(无根树)。

    2.将最小生成树构造为有根数,并用倍增LCA求出每个节点到第2^i个祖先的路径上的最长边。



    代码如下:

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    #include <vector>
    #include <cmath>
    #include <queue>
    #include <stack>
    #include <map>
    #include <string>
    #include <set>
    #define ms(a,b) memset((a),(b),sizeof((a)))
    using namespace std;
    typedef long long LL;
    const int INF = 2e9;
    const LL LNF = 9e18;
    const int mod = 1e9+7;
    const int maxn = 3e4+10;
    const int DEG = 20;
    
    struct node
    {
        int u, v, w;
        bool operator<(const node &x)const {
            return w<x.w;
        }
    }e[maxn];
    
    struct edge
    {
        int to, w, next;
    }edge[maxn*2];
    
    int n, m,k;
    int head[maxn], tot;
    int fa[maxn][DEG], deg[maxn], ma[maxn][DEG], be[maxn];
    
    int find(int x) { return be[x]==x?x:x=find(be[x]); }
    
    void add(int u, int v, int w)
    {
        edge[tot].to = v;
        edge[tot].w = w;
        edge[tot].next = head[u];
        head[u] = tot++;
    }
    
    void bfs(int root)
    {
        queue<int>que;
        deg[root] = 0;
        ma[root][0] = 0;
        fa[root][0] = root;
        que.push(root);
        while(!que.empty())
        {
            int tmp = que.front();
            que.pop();
            for(int i = 1; i<DEG; i++)
                fa[tmp][i] = fa[fa[tmp][i-1]][i-1], ma[tmp][i] = max( ma[tmp][i-1], ma[fa[tmp][i-1]][i-1]);
            for(int i = head[tmp]; i!=-1; i = edge[i].next)
            {
                int v = edge[i].to, w = edge[i].w;
                if(v==fa[tmp][0]) continue;
                deg[v] = deg[tmp]+1;
                fa[v][0] = tmp;
                ma[v][0] = w;
                que.push(v);
            }
        }
    }
    
    int LCA(int u, int v)
    {
        int ans = 0;
        if(deg[u]>deg[v]) swap(u,v);
        int hu = deg[u], hv = deg[v];
        int tu = u, tv = v;
        for(int det = hv-hu, i = 0; det; det>>=1, i++)
            if(det&1)
                ans = max(ans, ma[tv][i]), tv = fa[tv][i];
    
        if(tv==tu) return ans;
        for(int i = DEG-1; i>=0; i--)
        {
            if(fa[tu][i]==fa[tv][i]) continue;
            ans = max(ans, max( ma[tu][i], ma[tv][i] ) );
            tu = fa[tu][i];
            tv = fa[tv][i];
        }
        return ans = max(ans, max( ma[tu][0], ma[tv][0]) );
    }
    
    int main()
    {
        tot = 0;
        ms(head, -1);
        ms(ma,0);
        scanf("%d%d%d",&n,&m,&k);
        for(int i = 0; i<m; i++)
            scanf("%d%d%d",&e[i].u,&e[i].v,&e[i].w);
    
        sort(e,e+m);
        for(int i = 1; i<=n; i++)
            be[i] = i;
        for(int i = 0; i<m; i++)
        {
            int u = find(e[i].u), v = find(e[i].v);
            if(u!=v)
            {
                be[u] = v;
                add(e[i].u, e[i].v, e[i].w);
                add(e[i].v, e[i].u, e[i].w);
            }
        }
    
        bfs(1);
        for(int i = 0; i<k; i++)
        {
            int u, v;
            scanf("%d%d",&u,&v);
            printf("%d
    ",LCA(u,v));
        }
    }
    


  • 相关阅读:
    【STM32】串行通信原理
    【STM32】NVIC中断优先级管理
    【Linux-驱动】RTC设备驱动架构
    【Linux-驱动】在sysfs下创建对应的class节点---class_create
    【Linux-驱动】将cdev加入到系统中去---cdev_add
    【Linux-驱动】简单字符设备驱动结构和初始化
    【Linux-驱动】printk的打印级别
    【Linux 网络编程】REUSADDR
    【Linux 网络编程】常用TCP/IP网络编程函数
    linux定时重启tomcat脚本
  • 原文地址:https://www.cnblogs.com/DOLFAMINGO/p/7538643.html
Copyright © 2011-2022 走看看