[BZOJ 2561]最小生成树
转载请注明出处:http://danihao123.is-programmer.com/
窝只会做水体了qwq
因为这条边既存在在最大生成树里,又存在在最小生成树里。那就说明\(u\)到\(v\)的路径上,在最大生成树上这条边是最小的,在最小生成树上这条边是最大的。
所以说我们不能用大于\(L\)的边来联通\(u\)和\(v\),也不能用小于\(L\)的边,于是乎……跑两次最小割即可。
代码:
/************************************************************** Problem: 2561 User: danihao123 Language: C++ Result: Accepted Time:1528 ms Memory:15952 kb ****************************************************************/ #include <cstdio> #include <cstring> #include <cstdlib> #include <cctype> #include <utility> #include <algorithm> #include <queue> const int maxn = 20005; const int maxm = 200005; const int maxe = maxm << 2; int n, m; int first[maxn]; int next[maxe], to[maxe], flow[maxe], cap[maxe]; int gcnt = 0; inline void init_graph() { gcnt = 0; std::fill(first + 1, first + 1 + n, 0); } inline void add_edge(int u, int v, int f) { gcnt ++; next[gcnt] = first[u]; first[u] = gcnt; to[gcnt] = v; flow[gcnt] = 0; cap[gcnt] = f; } inline int rev(int i) { return (((i - 1) ^ 1) + 1); } inline void ins_edge(int u, int v, int f) { add_edge(u, v, f); add_edge(v, u, 0); } int line[maxm][3]; int d[maxn]; int s, t; inline bool bfs() { static bool vis[maxn]; std::fill(vis + 1, vis + 1 + n, false); std::fill(d + 1, d + 1 + n, 0); std::queue<int> Q; Q.push(s); vis[s] = true; d[s] = 1; while(!Q.empty()) { int u = Q.front(); Q.pop(); for(int i = first[u]; i; i = next[i]) { int v = to[i]; if(!vis[v] && cap[i] > flow[i]) { d[v] = d[u] + 1; vis[v] = true; Q.push(v); } } } return vis[t]; } int cur[maxn]; int dfs(int x, int a) { if(a == 0 || x == t) return a; int ans = 0; for(int &i = cur[x]; i; i = next[i]) { int v = to[i]; int f; if(d[v] == d[x] + 1 && (f = dfs(v, std::min(a, cap[i] - flow[i]))) > 0) { ans += f; a -= f; flow[i] += f; flow[rev(i)] -= f; if(a == 0) break; } } if(a > 0) d[x] = -1; return ans; } int dinic() { int ans = 0; while(bfs()) { for(int i = 1; i <= n; i ++) cur[i] = first[i]; ans += dfs(s, 0x7fffffff); } return ans; } int main() { scanf("%d%d", &n, &m); for(int i = 1; i <= m; i ++) { int *l = line[i]; scanf("%d%d%d", &l[0], &l[1], &l[2]); } int L; scanf("%d%d%d", &s, &t, &L); for(int i = 1; i <= m; i ++) { int *l = line[i]; if(l[2] < L) { ins_edge(l[0], l[1], 1); ins_edge(l[1], l[0], 1); } } int ans = dinic(); init_graph(); for(int i = 1; i <= m; i ++) { int *l = line[i]; if(l[2] > L) { ins_edge(l[0], l[1], 1); ins_edge(l[1], l[0], 1); } } ans += dinic(); printf("%d\n", ans); return 0; }