论文《最小割模型在信息学竞赛中的应用》原题
二进制不同位上互不影响,那么就按位跑网络流
每一位上,确定的点值为1的与S连一条容量为INF的有向边。为0的与T连一条容量为INF的有向边。
其他的按给定的无向图建边,容量为1。
统计答案是从源点能到达的点(流量未达到容量)即为该位上为1的点。
需要跑多少遍根据所有权值的最高位来确定。直接跑30次TLE了。
#include <bits/stdc++.h> using namespace std; inline int read() { int x = 0, f = 1; char ch = getchar(); while (ch < '0' || ch > '9') { if (ch == '-') f = -1; ch = getchar(); } while (ch >= '0' && ch <= '9') { x = x * 10 + ch - 48; ch = getchar(); } return x * f; } const int INF = 0x3f3f3f3f; const int N = 2e5 + 10; struct Edge { int v, next, f; } edge[N]; struct IN { int u, v; } in[N]; int head[N], cnt, level[N], iter[N], n, m; int a[N], res[N]; bool vis[N]; vector<int> appear; inline void add(int u, int v, int f) { edge[cnt].v = v; edge[cnt].f = f; edge[cnt].next = head[u]; head[u] = cnt++; } bool bfs(int s, int t) { for (int i = 0; i <= t; i++) level[i] = -1, iter[i] = head[i]; queue<int> que; que.push(s); level[s] = 0; while (!que.empty()) { int u = que.front(); que.pop(); for (int i = head[u]; ~i; i = edge[i].next) { int v = edge[i].v, f = edge[i].f; if (level[v] < 0 && f) { que.push(v); level[v] = level[u] + 1; } } } return level[t] != -1; } int dfs(int u, int t, int f) { if (u == t || !f) return f; int flow = 0; for (int i = iter[u]; ~i; i = edge[i].next) { iter[u] = i; int v = edge[i].v; if (level[v] == level[u] + 1 && edge[i].f) { int w = dfs(v, t, min(f, edge[i].f)); if (!w) continue; flow += w; f -= w; edge[i].f -= w; edge[i^1].f += w; if (f <= 0) break; } } return flow; } int dinic(int s, int t) { int ans = 0; while (bfs(s, t)) ans += dfs(s, t, INF); return ans; } void get_ans(int u, int bit) { vis[u] = 1; res[u] += 1 << bit; for (int i = head[u]; ~i; i = edge[i].next) { int v = edge[i].v; if (!vis[v] && edge[i].f) { get_ans(v, bit); } } } void solve(int bit, int s, int t) { for (int i = 0; i <= t; i++) head[i] = -1, vis[i] = false; cnt = 0; for (int i = 0, sz = appear.size(); i < sz; i++) { int x = appear[i]; if ((1 << bit) & a[x]) { add(s, x, INF); add(x, s, 0); } else { add(x, t, INF); add(t, x, 0); } } for (int i = 1; i <= m; i++) { add(in[i].u, in[i].v, 1); add(in[i].v, in[i].u, 1); } dinic(s, t); get_ans(s, bit); } inline void init() { for (int i = 0; i <= n; i++) { res[i] = a[i] = 0; } appear.clear(); } int main() { int T = read(); while (T--) { n = read(), m = read(); init(); int s = 0, t = n + 1; int mak = 0; for (int i = 1; i <= m; i++) { in[i].u = read(), in[i].v = read(); } int k = read(); while (k--) { int u = read(); a[u] = read(); appear.emplace_back(u); } for (int i = 0, sz = appear.size(); i < sz; i++) { int u = appear[i]; int temp = a[u]; int bit = 0; while (temp) { bit++; temp >>= 1; } mak = max(bit, mak); } for (int i = 0; i <= mak; i++) { solve(i, s, t); } for (int i = 1; i <= n; i++) printf("%d\n", res[i]); } }