101889I Imperial roads (最小生成樹+LCA)
阿新 • • 發佈:2018-12-13
先求出最小生成樹來,如果必須要修的邊在最小生成樹上,直接輸出最小生成樹的值就行了,否則必須修的邊肯定會和最小生成樹上的邊形成一個環,刪掉這條環上的除了這條邊以外的最大邊就行了,問題就轉化為求瓶頸路問題了,之前用樸素的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; }