题意:
给出一幅无向带权图,q次询问,每次询问都求一棵包含给出的边的最小生成树。
思路:
首先求出最小生成树(kruskal),如果查询的边在最小生成树上,肯定是直接输出最小生成树,如果不在树上,那么这条必须连的边会和生成树形成一个环,我们就要去掉这个环上最大的一条边,就得到了答案(最小生成树是通过局部最优解得到全局最优解的,所以如果这样做,得到的是符合要求的最优解)。
赛中队友提出一个问题,如果有两棵不同的最小生成树那这个做法不就错了吗,但其实如果有两棵最小生成树,这两棵树 相同权值的边的条数是一样的,是同分异构,所以做法还是正确的。
而求环上的最大值,其实是求树上的最大值,所以在做kruskal的时候建立一幅新图,然后用lca求最大值。注意最大值的更新,很容易错。
#include<cstdio> #include<algorithm> #include<iostream> #include<vector> #include<map> #include<set> #include<cstring> #include<queue> #include<stack> #include<cmath> #define CLR(a,b) memset(a,b,sizeof(a)) #define mkp(a,b) make_pair(a,b) using namespace std; const int maxn = 100010; typedef long long ll; int n, m, head[maxn], tot, vis[maxn],fa[maxn],deep[maxn],t,f[maxn][20],ma[maxn][20]; int ans; struct edge { int to, w, Next; edge() {} edge(int to, int Next, int w) :to(to), Next(Next), w(w) {} }a[maxn * 4]; map<pair<int, int >, int >mp; struct node { int u, v, w; node(int u, int v, int w) :u(u), v(v), w(w) {} }; vector<node>g; void addv(int u, int v, int w) { a[++tot] = { v,head[u],w }; head[u] = tot; } void init() { CLR(head, -1); for (int i = 1; i <= n; i++)fa[i] = i; tot = 0; } int find(int x) { return x == fa[x] ? x : fa[x] = find(fa[x]); } inline void baba(int x, int y) { int fx = find(x), fy = find(y); fa[fx] = fy; } bool cmp(node &a, node &b) { return a.w < b.w; } inline void kruskal() { sort(g.begin(), g.end(), cmp); for (int i = 0; i < m; i++) { int x = find(g[i].u); int y = find(g[i].v); if (x == y)continue; addv(g[i].u, g[i].v, g[i].w); addv(g[i].v, g[i].u, g[i].w); baba(x, y); ans += g[i].w; } } inline void bfs() { queue<int >q; q.push(1); deep[1] = 1; while (!q.empty()) { int x = q.front(); q.pop(); for (int i = head[x]; i != -1; i = a[i].Next) { int y = a[i].to; if (deep[y])continue; deep[y] = deep[x] + 1; f[y][0] = x; ma[y][0] = a[i].w; for (int j = 1; j <= t; j++) { f[y][j] = f[f[y][j - 1]][j - 1]; ma[y][j] = max(ma[y][j-1], ma[f[y][j - 1]][j - 1]); } q.push(y); } } } int lca(int x, int y) { int maxx = 0; if (deep[x] > deep[y])swap(x, y); for (int i = t; i >= 0; i--) { if (deep[f[y][i]] >= deep[x]) { maxx = max(maxx, ma[y][i]); y = f[y][i]; } } if (x == y)return maxx; for (int i = t; i >= 0; i--) { if (f[x][i] != f[y][i]) { maxx = max(maxx, ma[x][i]); maxx = max(maxx, ma[y][i]); x = f[x][i], y = f[y][i]; } } //printf("debug "); maxx=max(maxx,ma[x][0]); maxx=max(maxx,ma[y][0]); return maxx; } int main() { scanf("%d%d", &n, &m); init(); for(int i=1;i<=m;i++) { int u, v; int w; scanf("%d%d%d", &u, &v, &w); if (u > v)swap(u, v); mp[make_pair(u, v)] = w; g.push_back(node{ u,v,w }); } kruskal(); t = (int)(log(n) / log(2)) + 1; bfs(); // for (int i = 1; i <= n; i++) // { // printf("i:%d deep:%d ", i, deep[i]); // } int q; cin >> q; while (q--) { int u, v; scanf("%d%d", &u, &v); if (u > v)swap(u, v); // printf("u:%d v:%d ", u, v); // printf("ans:%d lca:%d mp:%d ",ans,lca(u,v),mp[make_pair(u,v)]); printf("%d ", ans - lca(u, v)+mp[make_pair(u,v)]); } } /* 5 7 1 2 6 1 3 4 3 4 2 1 5 7 4 5 4 2 4 1 3 5 3 1 4 5 */