SCU 4584 tarjan+最大权闭合子图

把每个点的点权当做是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;
}
View Code

猜你喜欢

转载自www.cnblogs.com/Aragaki/p/10629691.html