把每个点的点权当做是W[i]-V[i] 题目一眼是最大权闭合子图 但是可能会有重边自环和环 需要先搞成简单图 再tarjan缩点 缩点后就是裸的最大权闭合子图
#include<bits/stdc++.h> using namespace std; typedef long long ll; const int MAXN = 105000; const int MAXM = 1000005; const ll INF = 200000000050000LL; int Head[MAXN], cur[MAXN], lev[MAXN], to[MAXM << 1], nxt[MAXM << 1], ed, S, T; ll f[MAXM << 1]; inline void addedge2(int u, int v) { to[++ed] = v; nxt[ed] = Head[u]; Head[u] = ed; return; } inline void addedge(int u, int v, ll cap) { to[++ed] = v; nxt[ed] = Head[u]; Head[u] = ed; f[ed] = cap; to[++ed] = u; nxt[ed] = Head[v]; Head[v] = ed; f[ed] = 0; return; } inline bool BFS() { int u; memset(lev, -1, sizeof(lev)); queue<int>q; lev[S] = 0; q.push(S); while (q.size()) { u = q.front(); q.pop(); for (int i = Head[u]; i; i = nxt[i]) if (f[i] && lev[to[i]] == -1) { lev[to[i]] = lev[u] + 1; q.push(to[i]); /* if (to[i] == T) { return 1; } magic one way optimize */ } } memcpy(cur, Head, sizeof Head); return lev[T] != -1; } inline ll DFS(int u, ll maxf) { if (u == T || !maxf) { return maxf; } ll cnt = 0, tem; for (int &i = cur[u]; i; i = nxt[i]) if (f[i] && lev[to[i]] == lev[u] + 1) { tem = DFS(to[i], min(maxf, f[i])); maxf -= tem; f[i] -= tem; f[i ^ 1] += tem; cnt += tem; if (!maxf) { break; } } if (!cnt) { lev[u] = -1; } return cnt; } ll Dinic() { ll ans = 0; while (BFS()) { ans += DFS(S, INF); } return ans; } void init(int SS, int TT) { ed = 1; S = SS; T = TT; return; } //Directed tarjan(without repeat edge) int deep, colorsum = 0; int top;/*sta目前的大小*/ int dfn[MAXN], color[MAXN], low[MAXN]; int sta[MAXN];//存着当前所有可能能构成强连通分量的点 bool visit[MAXN];//表示一个点目前是否在sta中 int cnt[MAXN];//各个强连通分量中含点的数目 ll valsum[MAXN]; void tarjan(int x) { dfn[x] = ++deep; low[x] = deep; visit[x] = 1; sta[++top] = x; for (int i = Head[x]; i; i = nxt[i]) { int v = to[i]; if (!dfn[v]) { tarjan(v); low[x] = min(low[x], low[v]); } else { if (visit[v]) { low[x] = min(low[x], low[v]); } } } if (dfn[x] == low[x]) { color[x] = ++colorsum; visit[x] = 0; while (sta[top] != x) { color[sta[top]] = colorsum; visit[sta[top--]] = 0; } top--; } } ll w[MAXN]; pair<int, int> Edge[MAXM]; map<pair<int, int>, int> mp; int main() { int n, m, x; int u, v, c; int TNT; scanf("%d", &TNT); while (TNT--) { mp.clear(); scanf("%d %d", &n, &m); top = colorsum = 0; for (int i = 0; i <= n + 1; i++) { visit[i] = dfn[i] = low[i] = cnt[i] = color[i] = Head[i] = 0; valsum[i] = 0; } ed = 1; for (int i = 1; i <= n; i++) { scanf("%lld", &w[i]); } for (int i = 1; i <= n; i++) { scanf("%d", &x); w[i] -= x; } for (int i = 1; i <= m; i++) { scanf("%d %d", &u, &v); if (u == v || mp[make_pair(u, v)]) { Edge[i].first = u, Edge[i].second = u; continue; } mp[make_pair(u, v)] = 1; Edge[i].first = u, Edge[i].second = v; addedge2(u, v); } for (int i = 1; i <= n; i++) { if (!dfn[i]) { tarjan(i); } } for (int i = 1; i <= n; i++) { valsum[color[i]] += w[i]; } init(0, n + 1); for (int i = 0; i <= n + 1; i++) { Head[i] = 0; } ll anser = 0; for (int i = 1; i <= colorsum; i++) { if (valsum[i] > 0) { anser += valsum[i]; addedge(S, i, valsum[i]); } else if (valsum[i] < 0) { addedge(i, T, -valsum[i]); } } for (int i = 1; i <= m; i++) { u = Edge[i].first; v = Edge[i].second; if (color[u] == color[v]) { continue; } addedge(color[u], color[v], INF); } cout << anser - Dinic() << endl; } return 0; }
原文:https://www.cnblogs.com/Aragaki/p/10629691.html