[???]天上红绯

题目描述 Description
天上红绯在游戏中扮演敏剑,对于⾼攻击低防御的职业来说,爆发⼒显得⾮常重要,为此,她准备学习n个技能,每个技能都有2个学习⽅向:物理攻击和魔法攻击。对于第i个技能,如果选择物理攻击⽅向,会增加ap_i的爆发⼒,如果选择魔法攻击的⽅向,会增加ad_i的爆发⼒。此外,还有⼀些combo,⼀个combo由两个技能组成,对于第i个combo,如果他们都是魔法攻击,会额外增加AD_i的爆发⼒,如果他们都是物理攻击,会额外增加AP_i的爆发⼒,如果他们不属于同⼀类型,会减少AX_i的爆发⼒。她找到了你,请你帮她选择技能的类型,产⽣最⼤的爆发⼒
输入描述 Input Description

第⼀⾏2个正整数n,m,表⽰技能的个数和combo的个数接下来n⾏每⾏2个正整数,描述⼀个技能的ap_i,ad_i接下来m⾏每⾏5个正整数u,v,AD_i,AP_i,AX_i,描述⼀个combo,表⽰技能u和技能v产⽣combo

输出描述 Output Description
⼀⾏,⼀个整数,表⽰最⼤的爆发⼒
样例输入 Sample Input
2 1
50 5
10 20
1 2 100 50 50
样例输出 Sample Output
125
数据范围及提示 Data Size & Hint
测试点编号
   n      m
1  5      5
2  50     100
3  100000 0
4  500000 0
5  1000   3000
6  1000   3000
7  1000   3000
8  10000  40000
9  10000  40000
10 10000  40000

对于所有的测试点,确保不会爆long long

 根据套路,这是一道最小割的题,至于建图,依据经验,我们很容易想到对于每一个点i,s向i连一条物理攻击的边,i向t连一条魔法攻击的边,这肯定是没有问题的。之后我们考虑combo问题,回顾一下题意:如果他们都是魔法攻击,会额外增加AD_i的爆发⼒,如果他们都是物理攻击,会额外增加AP_i的爆发⼒,如果他们不属于同⼀类型,会减少AX_i的爆发⼒。首先肯定能想到comboi一定要与ui与vi有联系。考虑本题中割的意思,对于一个点i,割物理攻击的边表示i要使用魔法攻击,割魔法攻击的边表示i要使用物理攻击,而割的目的是为了使s与t不联通,砍掉一条通路才可以。对于一个combo,只有两个技能都用物理了才能启用APi的输出,于是我们尝试ui,vi分别向combo点连一条Api的双向边,combo再向t连一条APi的边。这样就能很好的解决问题。对于魔法攻击类似,所以对于每一个combo要开两个点。剩下AXi的关系那就很显然是ui与vi连一条双向边了,容量为AXi.

#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<queue>
using namespace std;
typedef long long LL;
#define mem(a,b) memset(a,b,sizeof(a))
inline LL read()
{
    LL x=0,f=1;char c=getchar();
    while(!isdigit(c)){if(c=='-')f=-1;c=getchar();}
    while(isdigit(c)){x=x*10+c-'0';c=getchar();}
    return x*f;
}
const int maxn=500010,maxm=40010;
const LL oo=999999999;
LL ad[maxn],ap[maxn],AD[maxm],AP[maxm],AX[maxm];
int n,m,u[maxn],v[maxn]; 
const int maxN=90010,maxM=400010;
struct Edge
{
    int u,v,next;LL f;
    Edge() {}
    Edge(int _1,int _2,LL _3,int _4): u(_1),v(_2),f(_3),next(_4) {}
}e[2*maxM];
struct Dinic
{
    int first[maxN],dis[maxN],cur[maxN],a,b,c,ce,N,s,t;
    bool vis[maxN];queue <int> Q;
    void addEdge(int a,int b,LL c)
    {
        e[++ce]=Edge(a,b,c,first[a]);first[a]=ce;
        e[++ce]=Edge(b,a,0,first[b]);first[b]=ce; 
    }
    void init_build()
    {
        mem(first,-1);ce=-1;
        s=n+2*m+1;t=n+2*m+2;
        for(int i=1;i<=n;i++)addEdge(s,i,ad[i]),addEdge(i,t,ap[i]);
        for(int i=1;i<=m;i++)
        {
            addEdge(s,n+2*i-1,AD[i]);addEdge(n+2*i,t,AP[i]);
            addEdge(u[i],v[i],AX[i]);addEdge(v[i],u[i],AX[i]);
            addEdge(n+2*i-1,u[i],oo);addEdge(n+2*i-1,v[i],oo);
            addEdge(u[i],n+2*i,oo);  addEdge(v[i],n+2*i,oo);
        }
        N=n+2*m+2;
    }
    bool bfs()
    {
        mem(dis,42);mem(vis,0);
        while(Q.size())Q.pop();
        dis[s]=0;vis[s]=1;Q.push(s);
        while(Q.size())
        {
            int now=Q.front();Q.pop();
            for(int i=first[now];i!=-1;i=e[i].next)
                if(e[i].f && !vis[e[i].v])
                {
                    Q.push(e[i].v);
                    dis[e[i].v]=dis[now]+1;
                    vis[e[i].v]=1;
                }
        }
        return vis[t];
    }
    LL dfs(int x,LL a)
    {
        if(x==t || a==0)return a;
        LL flow=0,tmp;
        for(int& i=cur[x];i!=-1;i=e[i].next)
            if(dis[x]+1==dis[e[i].v] && (tmp=dfs(e[i].v,min(a,e[i].f)))>0)
            {
                e[i].f-=tmp;e[i^1].f+=tmp;
                a-=tmp;flow+=tmp;
                if(a==0)break;
            }
        return flow;
    }
    LL maxflow()
    {
        LL flow=0;
        while(bfs())
        {
            for(int i=1;i<=N;i++)cur[i]=first[i];
            flow+=dfs(s,oo);
        }
        return flow;
    }
}fyh;
void solve1()
{
    LL ans=0;
    for(int i=1;i<=n;i++)ans+=max(ad[i],ap[i]);
    printf("%lld\n",ans);
    return;
}
void solve2()
{
     fyh.init_build();
     LL sum=0;
     for(int i=1;i<=n;i++)sum+=(ad[i]+ap[i]);
     for(int i=1;i<=m;i++)sum+=(AD[i]+AP[i]);
     printf("%lld",sum-fyh.maxflow());
}
int main()
{
    n=(int)read();m=(int)read();
    for(int i=1;i<=n;i++)ap[i]=read(),ad[i]=read();
    for(int i=1;i<=m;i++)u[i]=(int)read(),v[i]=(int)read(),AD[i]=read(),AP[i]=read(),AX[i]=read();
    if(m==0)solve1();   
    else solve2(); 
    return 0;
}
View Code

 

posted @ 2017-02-28 19:39  小飞淙的云端  阅读(378)  评论(0编辑  收藏  举报