zoukankan      html  css  js  c++  java
  • cf 1051F 树+图

    $des$
    给定一张 $n$ 个点 $m$ 条边的带权无向联通图,$q$ 次询问,每次询问 $u_i$ 到 $v_i$ 的最短
    路长度。
    $n,q <= 10^5, m - n <= 20$

    $sol$
    首先随便搞一棵生成树,那么会有一些边不在生成树上。
    把这些边的端点标记为特殊点。
    对于一个询问,如果最短路只经过生成树上的边,就可以直接计算。
    否则一定经过了一个特殊点,可以枚举这个特殊点,然后更新答案

    $code$

    #include <bits/stdc++.h>
    
    using namespace std;
    
    #define gc getchar()
    inline int read() {
        int x = 0; char c = gc;
        while(c < '0' || c > '9') c = gc;
        while(c >= '0' && c <= '9') x = x * 10 + c - '0', c = gc;
        return x;
    
    }
    
    #define LL long long
    #define Rep(i, a, b) for(int i = a; i <= b; i ++)
    
    const int N = 1e5 + 10;
    
    int Now;
    int cnt, head[N], cnt2, head2[N];
    struct Node {
        int u, v, w, nxt;
        bool used;
    } E[N], Gr[N << 1], G[N << 1];
    
    int n, m;
    int Nottree[50], tot;
    
    int fat[N];
    
    int Get(int x) {
        return fat[x] == x ? x : fat[x] = Get(fat[x]);
    }
    
    void Link(int u, int v, int w) {
        G[++ cnt].v = v; G[cnt].w = w; G[cnt].nxt = head[u]; head[u] = cnt;
    }
    
    void Link_g(int u, int v, int w) {
        Gr[++ cnt2].v = v; Gr[cnt2].w = w; Gr[cnt2].nxt = head2[u]; head2[u] = cnt2;
    }
    
    void Kruskal() {
        int js = 0;
        Rep(i, 1, m) {
            int u = E[i].u, v = E[i].v;
            int fau = Get(u), fav = Get(v);
            if(fau != fav) {
                fat[fau] = fav;
                js ++;
                Link(u, v, E[i].w);
                Link(v, u, E[i].w);
                E[i].used = 1;
            }
            if(js == n - 1) break;
        }
    }
    
    struct Short {
        LL u, dis_;
        bool operator < (const Short a) const {
            return this-> dis_ > a.dis_;
        }
    };
    LL dis[50][N];
    bool vis[N];
    priority_queue <Short> Q;
    
    void Dijkstra(int start) {
        Rep(i, 1, n) dis[Now][i] = 1e18, vis[i] = 0;
        Q.push((Short) {start, dis[Now][start] = 0});
        while(!Q.empty()) {
            Short tp = Q.top();
            Q.pop();
            if(vis[tp.u]) continue;
            vis[tp.u] = 1;
            for(int i = head2[tp.u]; ~ i; i = Gr[i].nxt) {
                int v = Gr[i].v;
                if(dis[Now][v] > dis[Now][tp.u] + Gr[i].w) {
                    dis[Now][v] = dis[Now][tp.u] + Gr[i].w;
                    Q.push((Short) {v, dis[Now][v]});
                }
            }
        }
    }
    
    int fa[N], size[N], son[N], topp[N];
    LL deep[N];
    
    void Dfs1(int u, int f_, LL dep) {
        size[u] = 1; fa[u] = f_; deep[u] = dep;
        for(int i = head[u]; ~ i; i = G[i].nxt) {
            int v = G[i].v;
            if(v == f_) continue;
            Dfs1(v, u, dep + G[i].w);
            size[u] += size[v];
            if(size[v] > size[son[u]]) son[u] = v;
        }
    }
    
    void Dfs2(int u, int tp) {
        topp[u] = tp;
        if(!son[u]) return ;
        Dfs2(son[u], tp);
        for(int i = head[u]; ~ i; i = G[i].nxt) {
            int v = G[i].v;
            if(v != fa[u] && v != son[u]) Dfs2(v, v);    
        }
    }
    
    inline int Lca(int x, int y) {
        int tpx = topp[x], tpy = topp[y];
        while(tpx != tpy) {
            if(deep[tpx] < deep[tpy]) swap(x, y), swap(tpx, tpy);
            x = fa[tpx], tpx = topp[x];
        }
        if(deep[x] < deep[y]) swap(x, y);
        return y;
    }
    
    int main() {
        n = read(), m = read();
        Rep(i, 1, n) head[i] = -1, head2[i] = -1;
        Rep(i, 1, n) fat[i] = i;
        Rep(i, 1, m) {
            int u = read(), v = read(), w = read();
            E[i] = (Node) {u, v, w, 0, 0};
            Link_g(u, v, w), Link_g(v, u, w);
        }
        
        Kruskal();
        Rep(i, 1, m) if(E[i].used == 0) Nottree[++ tot] = E[i].u, Nottree[++ tot] = E[i].v;
        
        Rep(i, 1, tot) {
            Now ++;
            Dijkstra(Nottree[i]);
        }
        
        Dfs1(1, 0, 1);
        Dfs2(1, 1);
        
        for(int q = read(); q; q --) {
            int u = read(), v = read();
            LL Answer = deep[u] + deep[v] - 2 * deep[Lca(u, v)];
            Rep(i, 1, tot) {
                Answer = min(Answer, dis[i][u] + dis[i][v]);
            }
            cout << Answer << '
    ';
        }
        
        return 0;
    }
  • 相关阅读:
    (4)UIView和父子控件
    (2)第一个IOS程序
    svn本地目录结构for window
    (1)xcode基本设置和控制器等介绍
    git版本控制 for window安装和命令行使用
    linux虚拟机如何配置网卡信息(确保两台服务器通信)
    linux系统中firewalld防火墙管理工具firewallcmd(CLI命令行)
    linux系统中firewalld防火墙管理工具firewallconfig(GUI图形用户界面)
    linux系统中使用nmtui命令配置网络参数(图形用户界面)
    网卡是什么?
  • 原文地址:https://www.cnblogs.com/shandongs1/p/9773248.html
Copyright © 2011-2022 走看看