传送门
由题可以得出一些关系。
- 如果对于同一行的相邻两个格子 ( i , j ) , ( i , j + 1 ) (i,j),(i,j+1) (i,j),(i,j+1),那么前者是后者的后继。
- 如果对于两个格子 A ( a , b ) , B ( c , d ) A(a,b),B(c,d) A(a,b),B(c,d),如果 A A A保护 B B B,那么 B B B是 A A A的后继。
然后可以发现如果以这样的方式建图会产生环。
并且由条件知整个环都不能选。
因此我们先在反向图上拓扑排序去掉环。
然后就是最大权闭合子图的裸板了。
代码:
#include<bits/stdc++.h>
#define N 500005
using namespace std;
inline int read(){
int ans=0,w=1;
char ch=getchar();
while(!isdigit(ch)){if(ch=='-')w=-1;ch=getchar();}
while(isdigit(ch))ans=(ans<<3)+(ans<<1)+(ch^48),ch=getchar();
return ans*w;
}
int n,m,val[N],du[N];
bool vis[N];
struct edge{int v,next,c;};
struct Dinic{
int first[N],cnt,cur[N],d[N],s,t;
edge e[N<<1];
inline void init(){memset(first,-1,sizeof(first)),s=0,cnt=-1,t=N-5;}
inline void addedge(int u,int v,int c){e[++cnt].v=v,e[cnt].next=first[u],e[cnt].c=c,first[u]=cnt;}
inline void add(int u,int v,int c){addedge(u,v,c),addedge(v,u,0);}
inline bool bfs(){
queue<int>q;
memset(d,-1,sizeof(d)),d[s]=0,q.push(s);
while(!q.empty()){
int x=q.front();
q.pop();
for(int i=first[x];~i;i=e[i].next){
int v=e[i].v;
if(~d[v]||!e[i].c)continue;
d[v]=d[x]+1,q.push(v);
}
}
return ~d[t];
}
inline int dfs(int x,int f){
if(!f||x==t)return f;
int flow=f;
for(int&i=cur[x];~i;i=e[i].next){
int v=e[i].v;
if(!flow)break;
if(e[i].c&&d[v]==d[x]+1){
int tmp=dfs(v,min(flow,e[i].c));
flow-=tmp,e[i].c-=tmp,e[i^1].c+=tmp;
if(!tmp)d[v]=-1;
}
}
return f-flow;
}
inline int solve(){
int ret=0;
while(bfs())memcpy(cur,first,sizeof(first)),ret+=dfs(s,0x3f3f3f3f);
return ret;
}
}dinic;
inline int idx(int a,int b){return (a-1)*m+b;}
vector<int>g[N],h[N];
inline void add(int u,int v){g[u].push_back(v),h[v].push_back(u),++du[v];}
int main(){
n=read(),m=read(),dinic.init();
for(int i=1;i<=n;++i)
for(int j=1;j<=m;++j){
val[idx(i,j)]=read();
int k=read();
while(k--){
int x=read()+1,y=read()+1;
add(idx(i,j),idx(x,y));
}
if(j>=2)add(idx(i,j),idx(i,j-1));
}
queue<int>q;
for(int i=1;i<=n*m;++i)if(!du[i])q.push(i);
while(!q.empty()){
int x=q.front();
q.pop(),vis[x]=1;
for(int i=0;i<g[x].size();++i){
--du[g[x][i]];
if(!du[g[x][i]])q.push(g[x][i]);
}
}
int ans=0;
for(int i=1;i<=n*m;++i){
if(!vis[i])continue;
if(val[i]>0)ans+=val[i],dinic.add(dinic.s,i,val[i]);
else dinic.add(i,dinic.t,-val[i]);
for(int j=0;j<h[i].size();++j)if(vis[h[i][j]])dinic.add(i,h[i][j],0x3f3f3f3f);
}
cout<<ans-dinic.solve();
return 0;
}