Gym - 101889I Imperial roads (最小生成树+LCA)

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/GYH0730/article/details/82933108

题目链接:https://cn.vjudge.net/contest/257313#problem/I

和这道题类似:https://blog.csdn.net/GYH0730/article/details/82827285

先求出最小生成树来,如果必须要修的边在最小生成树上,直接输出最小生成树的值就行了,否则必须修的边肯定会和最小生成树上的边形成一个环,删掉这条环上的除了这条边以外的最大边就行了,问题就转化为求瓶颈路问题了,之前用朴素的LCA写的,交在这个题t了,改用倍增LCA了

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 100005;
const int M = N << 2;
int n, m, head[N], mm;
int len[N];
struct Edge {
    int to, next, w;
}e[N << 1];
struct EE {
    int u, v, w;
}E[M];
bool cmp(EE a, EE b) { return a.w < b.w; }
void add(int u, int v, int w)
{
    e[mm].to = v;
    e[mm].w = w;
    e[mm].next = head[u];
    head[u] = mm++;
}
int sz[N], dep[N];
int f[N][22]; /// f[i][j] 表示 i 的第 2^j 个祖先
int dp[N][22];
void dfs(int u, int fa) /// 点从 1 开始标号
{
    f[u][0] = fa;
    sz[u] = 1;
    for (int i=head[u];~i;i=e[i].next)
    {
        int v = e[i].to;
        if (v != fa)
        {
            dep[v] = dep[u] + 1;
            len[v] = len[u] + e[i].w;
            dp[v][0] = e[i].w;
            dfs(v, u);
            sz[u] += sz[v];
        }
    }
}
int maxh;
void gao()
{
    int j;
    for (j=1;(1<<j)<n;j++)
        for (int i=1;i<=n;i++)
    {
        int t = f[i][j-1];
        f[i][j] = f[f[i][j-1]][j-1];
        dp[i][j] = max(dp[i][j-1], dp[t][j-1]);
    }
    maxh = j - 1;
}
int swim(int x, int k, int &ma)   /// 返回 x 的第 k 个祖先
{
    ma = 0;
    for (int i=0;i<=maxh;i++)
        if (k >> i & 1)
    {
        ma = max(ma, dp[x][i]);
        x = f[x][i];
    }
    return x;
}
int LCA(int x, int y)
{
    if (dep[x] > dep[y]) swap(x, y); ///dep[x] <= dep[y];
    int ans = 0;
    y = swim(y, dep[y] - dep[x], ans);

    if (x == y) return ans;
    for (int i=maxh; i>=0; i--) {
        if (f[x][i] != f[y][i])
        {
            ans = max(ans, max(dp[x][i], dp[y][i]));
            x = f[x][i], y = f[y][i];
        }
    }
    return max(ans, max(dp[x][0], dp[y][0]) ); //f[x][0];
}
int fa[N];
int find(int x) { return x==fa[x] ? x : fa[x]=find(fa[x]); }
map<int,int> mp1[N],mp2[N];
int main(void)
{
    while (scanf("%d %d",&n,&m) != EOF) {
        dep[1] = 0;
        len[1] = 0;
        dp[1][0] = 0;
        int sum = 0;
        for (int i=1;i<=n;i++) {
            fa[i] = i;
            mp1[i].clear();
            mp2[i].clear();
        }
        mm = 0;
        for (int i=0;i<m;i++) {
            scanf("%d%d%d", &E[i].u, &E[i].v, &E[i].w);
            if(E[i].u > E[i].v) swap(E[i].u,E[i].v);
            mp1[E[i].u][E[i].v] = E[i].w;
        }
        sort(E, E+m, cmp);
        memset(head, -1, sizeof head);
        int cnt = 0;
        for (int i=0;i<m;i++) {
            int a=find(E[i].u), b=find(E[i].v);
            if (a - b) {
                fa[a] = b;
                add(E[i].u, E[i].v, E[i].w);
                add(E[i].v, E[i].u, E[i].w);
                mp2[E[i].u][E[i].v] = 1;
                sum += E[i].w;
                if (++cnt == n-1) break;
            }
        }
        dfs(1, 0);
        gao();
        int Q;
        scanf("%d", &Q);
        while (Q--) {
            int a, b;
            scanf("%d%d",&a,&b);
            if(a > b) swap(a,b);
            if(mp2[a][b]) printf("%d\n",sum);
            else {
                int c = LCA(a, b);
                printf("%d\n",sum - c + mp1[a][b]);
            }
        }
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/GYH0730/article/details/82933108