Description

Input

Output

仅包含一个整数,表示可以获得的最大能源收入。注意,你也可以选择不进行任何攻击,这样能源收入为0。

Sample Input

3 2
10 0
20 0
-10 0
-5 1 0 0
100 1 2 1
100 0

Sample Output

25

HINT

在样例中, 植物P1,1可以攻击位置(0,0), P2,0可以攻击位置(2,1)
一个方案为,首先进攻P1,1,P0,1,此时可以攻击P0,0 。共得到能源收益为(5)+20+10=25。注意, 位置(2,1)被植物P2,0保护,所以无法攻击第2行中的任何植物。

大致数据规模

约20%的数据满足1N,M5
约40%的数据满足1N,M10
约100%的数据满足1N201M3010000Score10000

Source

思路

典型的二元组建图,注意有些地方永远都不能攻击到,需要先拓扑排序判断这些点,从网络流中剔除出这些点。

代码

#include <cstdio>
#include <cstring>
#include <queue>
#include <algorithm>

const int maxn=600;
const int maxm=400000;
const int inf=0x3f3f3f3f;

inline int read()
{
    int x=0,f=1;
    char ch=getchar();
    while((ch<'0')||(ch>'9'))
    {
        if(ch=='-')
        {
            f=-f;
        }
        ch=getchar();
    }
    while((ch>='0')&&(ch<='9'))
    {
        x=x*10+ch-'0';
        ch=getchar();
    }
    return x*f;
}

int n,m,s,t;

struct network_flow
{
    int pre[maxm+10],now[maxn+10],son[maxm+10],tot,val[maxm+10],d[maxn+10];

    inline int clear()
    {
        memset(now,0,sizeof now);
        tot=1;
        return 0;
    }

    inline int ins(int a,int b,int c)
    {
        pre[++tot]=now[a];
        now[a]=tot;
        son[tot]=b;
        val[tot]=c;
        return 0;
    }

    inline int add(int a,int b,int c)
    {
        ins(a,b,c);
        ins(b,a,0);
        return 0;
    }

    inline int bfs()
    {
        std::queue<int> q;
        q.push(s);
        memset(d,-1,sizeof d);
        d[s]=0;
        while(!q.empty())
        {
            int u=q.front(),j=now[u];
            q.pop();
            while(j)
            {
                int v=son[j];
                if(val[j]&&(d[v]==-1))
                {
                    d[v]=d[u]+1;
                    if(v==t)
                    {
                        return 1;
                    }
                    q.push(v);
                }
                j=pre[j];
            }
        }
        return 0;
    }

    int dfs(int u,int flow)
    {
        if(u==t)
        {
            return flow;
        }
        int j=now[u],res=flow;
        while(j&&res)
        {
            int v=son[j];
            if(val[j]&&(d[v]==d[u]+1))
            {
                int k=dfs(v,std::min(res,val[j]));
                if(!k)
                {
                    d[v]=-1;
                }
                val[j]-=k;
                val[j^1]+=k;
                res-=k;
            }
            j=pre[j];
        }
        return flow-res;
    }

    inline int dinic()
    {
        int ans=0;
        while(bfs())
        {
            ans+=dfs(s,inf);
        }
        return ans;
    }
};

struct graph
{
    int pre[maxm+10],now[maxn+10],son[maxm+10],tot,b[maxn+10],ru[maxn+10],stack[maxn+10],head;

    inline int clear()
    {
        memset(now,0,sizeof now);
        tot=0;
        return 0;
    }

    inline int ins(int a,int bx)
    {
        pre[++tot]=now[a];
        now[a]=tot;
        son[tot]=bx;
        ru[bx]++;
        return 0;
    }

    inline int graph_sort()
    {
        head=0;
        memset(b,0,sizeof b);
        for(register int i=1; i<=n*m; ++i)
        {
            if(!ru[i])
            {
                stack[++head]=i;
                b[i]=1;
            }
        }
        while(head)
        {
            int u=stack[head--],j=now[u];
            while(j)
            {
                int v=son[j];
                --ru[v];
                if(!ru[v])
                {
                    stack[++head]=v;
                    b[v]=1;
                }
                j=pre[j];
            }
        }
        return 0;
    }
};

network_flow f;
graph g;
int ans,score[maxn+10],minnum;

int main()
{
    n=read();
    m=read();
    s=0;
    t=n*m+1;
    minnum=inf;
    g.clear();
    f.clear();
    for(register int i=1; i<=n*m; ++i)
    {
        score[i]=read();
        minnum=std::min(minnum,score[i]);
        int k=read();
        while(k--)
        {
            int x=read(),y=read();
            g.ins(i,x*m+y+1);
        }
    }
    if(minnum>=0)
    {
        minnum=0;
    }
    else
    {
        minnum=-minnum;
    }
    for(register int i=0; i<n; ++i)
    {
        for(register int j=1; j<m; ++j)
        {
            g.ins(i*m+j+1,i*m+j);
        }
    }
    g.graph_sort();
    for(register int i=1; i<=n*m; ++i)
    {
        if(g.b[i])
        {
            f.add(i,t,score[i]+minnum);
            f.add(s,i,minnum);
            int j=g.now[i];
            while(j)
            {
                int v=g.son[j];
                if(g.b[v])
                {
                    f.add(i,v,inf);
                }
                j=g.pre[j];
            }
            ans+=score[i]+minnum;
        }
    }
    printf("%d\n",ans-f.dinic());
    return 0;
}