如果$x$可以攻击$y$,那么选了$y$就一定要选$x$,并且选了$x$就一定要选$x$右边的格子,格子还有权值,这就是最大权闭合子图的模型了,但是注意到图中可能存在环,直接拓扑排序忽略环即可
在这篇博客上看到一个对最大权闭合子图建图的解释,感觉很妙
对于每个正权点,如果它有$\infty$的边连向负权点,代表要得到这个正权点必须付出负权点的代价
在最大闭合子图的建图中,$S\rightarrow$正权点$\mathop\rightarrow\limits^\infty$负权点$\rightarrow T$是一条路径,必须被割掉一条边,割掉正权点的入边表示不要这个正权点,割掉负权点的出边表示付出负权点的代价获得正权点,所以答案是正权点点权之和减去最小割
#include<stdio.h>
#include<string.h>
const int inf=100000000;
int min(int a,int b){return a<b?a:b;}
namespace g1{
int h[610],nex[600010],to[600010],d[610],q[600010],M,n;
bool ok[610];
void add(int a,int b){
M++;
to[M]=b;
d[b]++;
nex[M]=h[a];
h[a]=M;
}
void sort(){
int head,tail,x,i;
head=1;
tail=0;
for(i=1;i<=n;i++){
if(d[i]==0){
tail++;
q[tail]=i;
ok[i]=1;
}
}
while(head<=tail){
x=q[head];
head++;
for(i=h[x];i;i=nex[i]){
d[to[i]]--;
if(d[to[i]]==0){
tail++;
q[tail]=to[i];
ok[to[i]]=1;
}
}
}
}
}
namespace g2{
int h[610],cur[610],to[2000010],nex[2000010],cap[2000010],dis[610],q[2000010],M=1,S,T;
void add(int a,int b,int c){
M++;
to[M]=b;
cap[M]=c;
nex[M]=h[a];
h[a]=M;
M++;
to[M]=a;
cap[M]=0;
nex[M]=h[b];
h[b]=M;
}
bool bfs(){
int head,tail,x,i;
memset(dis,-1,sizeof(dis));
head=tail=1;
q[1]=S;
dis[S]=0;
while(head<=tail){
x=q[head];
head++;
for(i=h[x];i;i=nex[i]){
if(cap[i]&&dis[to[i]]==-1){
dis[to[i]]=dis[x]+1;
if(to[i]==T)return 1;
tail++;
q[tail]=to[i];
}
}
}
return 0;
}
int dfs(int x,int flow){
if(x==T)return flow;
int i,f;
for(i=cur[x];i;i=nex[i]){
if(cap[i]&&dis[to[i]]==dis[x]+1){
f=dfs(to[i],min(flow,cap[i]));
if(f){
cap[i]-=f;
cap[i^1]+=f;
if(cap[i])cur[x]=i;
return f;
}
}
}
dis[x]=-1;
return 0;
}
int dicnic(){
int ans,tmp;
ans=0;
while(bfs()){
memcpy(cur,h,sizeof(h));
while(tmp=dfs(S,inf))ans+=tmp;
}
return ans;
}
}
int n,m,v[610];
int tr(int x,int y){return(x-1)*m+y;}
using namespace g1;
int main(){
int i,j,t,x,y,sum;
scanf("%d%d",&::n,&m);
g1::n=::n*m;
for(i=1;i<=g1::n;i++){
scanf("%d%d",v+i,&t);
while(t--){
scanf("%d%d",&x,&y);
add(i,tr(x+1,y+1));
}
}
for(i=1;i<=::n;i++){
for(j=1;j<m;j++)add(tr(i,j+1),tr(i,j));
}
sort();
using g2::S;
using g2::T;
using g2::add;
using g1::n;
S=n+1;
T=n+2;
sum=0;
for(x=1;x<=n;x++){
if(ok[x]){
if(v[x]>0){
sum+=v[x];
add(S,x,v[x]);
}else if(v[x]<0)
add(x,T,-v[x]);
for(i=h[x];i;i=nex[i]){
if(ok[to[i]])add(to[i],x,inf);
}
}
}
printf("%d",sum-g2::dicnic());
}