bzoj 2238
最小生成树 + 链剖
建立最小生成树
将所有不在最小生成树上的边的两点之间的边上加入该边的权值
每条边在加入权值时取最小
对于不在最小生成树上的边删去后最小生成树不变
对于在最小生成树上的边删去后的最小增量(相对于MST - 该边的权值)为两点之间路径的最小值
#include <bits/stdc++.h> const int N = 5e4 + 10, M = N << 1; int head[N], cnt = 1; struct Node_1 {int u, v, w, num; bool be_use;} E[M]; struct Node {int u, v, nxt;} G[N << 1]; int fa[N], tree[N], deep[N], size[N], son[N], topp[N], bel[M]; int n, m, T, tim; int Mst, father[N], Use_js; int Minn[N << 2]; bool Cmp_1(Node_1 a, Node_1 b) {return a.num < b.num;} bool Cmp(Node_1 a, Node_1 b) {return a.w < b.w;} int Get_fa(int x) {return father[x] == x ? x : father[x] = Get_fa(father[x]);} void Add(int u, int v) {G[cnt].v = v; G[cnt].nxt = head[u]; head[u] = cnt ++;} void Make_mst() { std:: sort(E + 1, E + m + 1, Cmp); for(int i = 1; i <= n; i ++) father[i] = i; for(int i = 1; i <= m; i ++) { int u = E[i].u, v = E[i].v, fa_u = Get_fa(u), fa_v = Get_fa(v); if(fa_u != fa_v) { E[i].be_use = 1; Use_js ++; father[fa_u] = fa_v; Mst += E[i].w; Add(E[i].u, E[i].v), Add(E[i].v, E[i].u); } if(Use_js == n - 1) return ; } } void Dfs_1(int u, int f_, int dep) { fa[u] = f_; deep[u] = dep; size[u] = 1; for(int i = head[u]; ~ i; i = G[i].nxt) { int v = G[i].v; if(v != f_) { Dfs_1(v, u, dep + 1); size[u] += size[v]; if(size[v] > size[son[u]]) son[u] = v; } } } void Dfs_2(int u, int tp) { tree[u] = ++ tim; topp[u] = tp; if(!son[u]) return ; Dfs_2(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]) Dfs_2(v, v); } } #define lson jd << 1 #define rson jd << 1 | 1 void Sec_G(int l, int r, int jd, int x, int y, int z) { if(x <= l && r <= y) { Minn[jd] = std:: min(Minn[jd], z); return ; } int mid = (l + r) >> 1; if(x <= mid) Sec_G(l, mid, lson, x, y, z); if(y > mid) Sec_G(mid + 1, r, rson, x, y, z); } void Sec_G_Imp(int x, int y, int w) { int tpx = topp[x], tpy = topp[y]; while(tpx != tpy) { if(deep[tpx] < deep[tpy]) std:: swap(x, y), std:: swap(tpx, tpy); Sec_G(1, n, 1, tree[tpx], tree[x], w); x = fa[tpx]; tpx = topp[x]; } if(x == y) return ; if(deep[x] < deep[y]) std:: swap(x, y); Sec_G(1, n, 1, tree[y] + 1, tree[x], w); } int Answer; void Poi_A(int l, int r, int jd, int x) { if(l == r) {Answer = Minn[jd]; return ;} Minn[lson] = std:: min(Minn[lson], Minn[jd]); Minn[rson] = std:: min(Minn[rson], Minn[jd]); int mid = (l + r) >> 1; if(x <= mid) Poi_A(l, mid, lson, x); else Poi_A(mid + 1, r, rson, x); } #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; } int main() { n = read(), m = read(); for(int i = 1; i <= n; i ++) head[i] = -1; for(int i = 1; i <= m; i ++) { E[i].u = read(), E[i].v = read(), E[i].w = read(); E[i].num = i; } T = read(); Make_mst(); if(Use_js != n - 1) {for(; T; T --) puts("Not connected"); return 0;} Dfs_1(1, 0, 1); Dfs_2(1, 1); for(int i = 1; i <= (N << 2); i ++) Minn[i] = 999999999; std:: sort(E + 1, E + m + 1, Cmp_1); for(int i = 1; i <= m; i ++) bel[i] = (deep[E[i].u] > deep[E[i].v] ? E[i].u : E[i].v); for(int i = 1; i <= m; i ++) if(!E[i].be_use) Sec_G_Imp(E[i].u, E[i].v, E[i].w); for(; T; T --) { int x = read(); if(!E[x].be_use) { printf("%d\n", Mst); continue ; } Answer = 999999999; Poi_A(1, n, 1, tree[bel[x]]); if(Answer == 999999999) puts("Not connected"); else printf("%d\n", Mst - E[x].w + Answer); } return 0; }