tarjan 版本,点在环上的条件应该是其所在强联通分量大小 ≥2,tarjan 完之后再 dfs 一遍来判断哪些点可以被攻击到
80 pts,WA On #5 #9
#include <iostream>
#include <algorithm>
#include <cstring>
#include <vector>
#include <queue>
#include <utility>
using namespace std;
// #define IS_ATCODER
// #define IS_MULTI_TESTS
// #define USE_CIN
#ifndef ONLINE_JUDGE
#include <atcoder/all>
using mint = atcoder::modint998244353;
#else
#ifdef IS_ATCODER
#include <atcoder/all>
using mint = atcoder::modint998244353;
#endif
#endif
#define mp make_pair
#define fi first
#define se second
#define sz(a) int(a.size())
using ll = long long;
using pii = pair <int, int>;
inline int read(){
int ret = 0;
char ch = ' ', c = getchar();
while(!('0' <= c && c <= '9')) ch = c, c = getchar();
while('0' <= c && c <= '9'){
ret = ret * 10 + (c ^ 48);
c = getchar();
}
return ch == '-' ? -ret : ret;
}
int n, m;
const int N = 600 + 100;
const int M = 2e6 + 10;
const ll INF = 0x3f3f3f3f3f3f3f3f;
int p[N];
vector<int> ed[N];
int dfn[N], ts = 0, low[N];
int stk[N], tt = 0;
bool instk[N];
int scc = 0, id[N], sz[N];
void tarjan(int u){
dfn[u] = ++ts;
low[u] = dfn[u];
stk[++tt] = u;
instk[u] = true;
for(auto v: ed[u]){
if(dfn[v] == 0){
tarjan(v);
low[u] = min(low[u], low[v]);
}
else if(instk[v]){
low[u] = min(low[u], dfn[v]);
}
}
if(dfn[u] == low[u]){
scc++;
int t;
do{
t = stk[tt--];
instk[t] = false;
id[t] = scc;
sz[scc]++;
} while(t != u);
}
}
bool vis[N];
void dfs(int u){
if(vis[u] || sz[id[u]] > 1) return ;
vis[u] = true;
for(auto v: ed[u]) dfs(v);
}
int to[M], nt[M], idx, h[N];
ll c[M];
inline void add(int x, int y, ll z){
to[idx] = y, nt[idx] = h[x], c[idx] = z, h[x] = idx++;
to[idx] = x, nt[idx] = h[y], c[idx] = 0, h[y] = idx++;
}
int S, T;
int cur[N], lv[N];
queue<int> que, empty_queue;
bool bfs(){
que = empty_queue;
memset(lv, -1, sizeof(lv));
lv[S] = 0;
cur[S] = h[S];
que.push(S);
while(!que.empty()){
int u = que.front();
que.pop();
for(int i = h[u]; i != -1; i = nt[i]){
int j = to[i];
if(lv[j] != -1 || c[i] == 0) continue;
lv[j] = lv[u] + 1;
cur[j] = h[j];
que.push(j);
if(j == T) return true;
}
}
return false;
}
ll find(int u, ll limit){
if(u == T) return limit;
ll flow = 0;
for(int i = cur[u]; flow < limit && i != -1; i = nt[i]){
cur[u] = i;
int j = to[i];
if(lv[j] != lv[u] + 1 || c[i] == 0) continue;
ll k = find(j, min(limit - flow, c[i]));
if(k == 0) lv[j] = -1;
flow += k;
c[i] -= k;
c[i ^ 1] += k;
}
return flow;
}
ll dinic(){
ll ans = 0, flow;
while(bfs()){
while(flow = find(S, INF)) ans += flow;
}
return ans;
}
void solve(){
memset(h, -1, sizeof(h));
n = read(), m = read();
auto ID = [=](int x, int y){
return (x - 1) * m + y;
};
for(int i = 1; i <= n; i++){
for(int j = 1; j <= m; j++){
int id = ID(i, j);
p[id] = read();
int cnt = read();
while(cnt--){
int x = read() + 1, y = read() + 1;
int id2 = ID(x, y);
ed[id].push_back(id2);
}
if(j >= 2) ed[id].push_back(id - 1);
}
}
for(int i = 1; i <= n; i++){
int id = ID(i, m);
if(dfn[id] == 0) tarjan(id);
}
for(int i = 1; i <= n; i++){
int id = ID(i, m);
if(!vis[id]) dfs(id);
}
for(int u = 1; u <= n * m; u++){
if(!vis[u]) continue;
for(auto v: ed[u]){
if(!vis[v]) continue;
// printf("add(%d, %d)\n", v, u);
add(v, u, INF);
}
}
S = 0, T = n * m + 1;
ll ans = 0;
for(int u = 1; u <= n * m; u++){
if(!vis[u]) continue;
if(p[u] > 0) add(S, u, p[u]), ans += p[u];
else if(p[u] < 0) add(u, T, -p[u]);
}
ans -= dinic();
printf("%lld\n", ans);
}
int main(){
#ifdef USE_CIN
ios::sync_with_stdio(0);
cin.tie(0),cout.tie(0);
#endif
#ifdef IS_MULTI_TESTS
int T;
#ifdef USE_CIN
cin >> T;
#else
T = read();
#endif
while(T--) solve();
#else
solve();
#endif
return 0;
}