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 << '\n';
    }
    
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/shandongs1/p/9773248.html