bzoj3206 [Apio2013]道路费用
传送门:http://www.lydsy.com/JudgeOnline/problem.php?id=3206
【题解】
我们发现可以先硬点给的边一定选,做一遍最小生成树,得到的其他边就是一定选的。
然后可以缩点了,图的大小是K。
我们枚举选择那些硬点的边。
我们先把硬点的边,加上新的连接连通块的边,这些边组成了一棵树。K+1个点K条边。
考虑我们有一条硬点的边,那么对于每条有用的边(u,v),u到v的路径上的值都不能超过(u,v)的值(考虑kruskal过程)
然后我们暴力维护每条边的值即可。。
你写倍增我不拦你呀qwq
复杂度O(mlogm+2^kk^2)
# include <stdio.h> # include <string.h> # include <algorithm> // # include <bits/stdc++.h> using namespace std; typedef long long ll; typedef long double ld; typedef unsigned long long ull; const int M = 5e5 + 10, N = 70; # define RG register # define ST static int n, m, K; ll ans = 0; struct edge{ int u, v, w; friend bool operator < (edge a, edge b) { return a.w < b.w; } }a[M], b[N], e[M]; int en = 0; ll v[M], sum[M]; bool ok[M]; int res[M], resn = 0, S; struct unionset { int fa[M]; inline void set() { for (int i=1; i<=n; ++i) fa[i] = i; } inline int getf(int x) { return fa[x] == x ? x : fa[x] = getf(fa[x]); } }A, B; int fa[M], mi[M], dep[M]; int head[M], nxt[M], to[M], tot; inline void add(int u, int v) { ++tot; nxt[tot] = head[u]; head[u] = tot; to[tot] = v; } inline void adde(int u, int v) { add(u, v), add(v, u); } inline void dfs(int x, int fat = 0) { fa[x] = fat; dep[x] = dep[fat] + 1; sum[x] = v[x]; for (int i=head[x]; i; i=nxt[i]) { if(to[i] == fat) continue; dfs(to[i], x); sum[x] += sum[to[i]]; } } inline void solve(int sta) { tot = 0; // printf("status = %d\n", sta); for (int i=1; i<=resn; ++i) { int x = res[i]; head[x] = 0; A.fa[x] = x; fa[x] = 0; mi[x] = 1e9; } for (int i=1; i<=K; ++i) if(sta & (1<<(i-1))) ok[i] = 1; else ok[i] = 0; for (int i=1; i<=K; ++i) if(ok[i]) { int u = A.getf(b[i].u), v = A.getf(b[i].v); if(u == v) return ; // 环 A.fa[u] = v; adde(b[i].u, b[i].v); } for (int i=1; i<=en; ++i) { int u = A.getf(e[i].u), v = A.getf(e[i].v); if(u == v) continue; A.fa[u] = v; adde(e[i].u, e[i].v); } dfs(S); for (int i=1; i<=en; ++i) { int u = e[i].u, v = e[i].v; if(dep[u] < dep[v]) swap(u, v); while(dep[u] != dep[v]) { mi[u] = min(mi[u], e[i].w); u = fa[u]; } while(u != v) { mi[u] = min(mi[u], e[i].w); mi[v] = min(mi[v], e[i].w); u = fa[u], v = fa[v]; } } ll cur = 0; for (int i=1; i<=K; ++i) { if(ok[i]) { int u = b[i].u, v = b[i].v; if(dep[u] < dep[v]) swap(u, v); cur += sum[u] * mi[u]; } } if(cur > ans) ans = cur; } int main() { scanf("%d%d%d", &n, &m, &K); A.set(), B.set(); for (int i=1; i<=m; ++i) scanf("%d%d%d", &a[i].u, &a[i].v, &a[i].w); sort(a+1, a+m+1); for (int i=1; i<=K; ++i) { scanf("%d%d", &b[i].u, &b[i].v); int u = A.getf(b[i].u), v = A.getf(b[i].v); A.fa[u] = v; } for (int i=1; i<=m; ++i) { int u = A.getf(a[i].u), v = A.getf(a[i].v); if(u != v) { A.fa[u] = v; u = B.getf(a[i].u), v = B.getf(a[i].v); B.fa[u] = v; } } S = B.getf(1); for (int i=1, t; i<=n; ++i) { scanf("%d", &t); v[B.getf(i)] += t; if(B.getf(i) == i) res[++resn] = i; } for (int i=1; i<=K; ++i) { b[i].u = B.getf(b[i].u); b[i].v = B.getf(b[i].v); } for (int i=1; i<=m; ++i) { // printf("====%d, %d\n", a[i].u, a[i].v); a[i].u = B.getf(a[i].u); a[i].v = B.getf(a[i].v); // printf("modified %d, %d\n", a[i].u, a[i].v); } for (int i=1; i<=m; ++i) { int u = B.getf(a[i].u), v = B.getf(a[i].v); if(u != v) ok[i] = 1, B.fa[u] = v; else ok[i] = 0; } for (int i=1; i<=m; ++i) if(ok[i]) e[++en] = a[i]; for (int sta=0; sta < (1<<K); ++sta) solve(sta); printf("%lld\n", ans); return 0; }