bzoj3875

用f[x]表示彻底把x消灭的代价

用g[x]表示把x的衍生物(不包括x)彻底杀死的代价

那么一开始f[x]就等于膜法攻击的代价,g[x]为膜法把x的衍生物逐个杀死的代价总和

之后不断用一个队列(类似SPFA的思想)不断更新维护f[x]就可以了

#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<queue>
#include<iostream>
using namespace std;
long long f[200005];//彻底 
long long g[200005];//衍生
long long pa[200005],mo[200005]; 
int first1[200005],first2[200005];
int len1=0,len2=0;
struct mod{int x,y,next;};
mod q1[1000005],q2[1000005];
queue<int>t;
bool v[200005];
int st=1,ed=1,n;
void ins1(int x,int y)
{
 len1++;
 q1[len1].x=x;
 q1[len1].y=y;
 q1[len1].next=first1[x];
 first1[x]=len1;
}
void ins2(int x,int y)
{
 len2++;
 q2[len2].x=x;
 q2[len2].y=y;
 q2[len2].next=first2[x];
 first2[x]=len2;    
}
void SPFA()
{
 while(!t.empty())
 {
  int x=t.front();
  t.pop();
  if (pa[x]+g[x]<f[x])
  {
   for (int j=first2[x];j!=0;j=q2[j].next)
   {
    int fa=q2[j].y;
    if (v[fa]==false)
    {
     t.push(fa);    
    }
    g[fa]=g[fa]-f[x]+pa[x]+g[x];
   }
   f[x]=pa[x]+g[x];
  }
  v[x]=false;
 }
}
int main()
{
 memset(first1,0,sizeof(first1));
 memset(first2,0,sizeof(first2));
 scanf("%d",&n);    
 for (int i=1;i<=n;i++)
 {
  int R;
  scanf("%lld%lld%d",&pa[i],&mo[i],&R);
  for (int j=1;j<=R;j++)
  {
   int y;
   scanf("%d",&y);
   ins1(i,y);
   ins2(y,i);
  }
 }
 for (int i=1;i<=n;i++)
 {
  f[i]=mo[i];
  t.push(i);
  v[i]=true;
  g[i]=0;
 }
 for (int x=1;x<=n;x++)
 {
  for (int j=first1[x];j!=0;j=q1[j].next)
  {
   int y=q1[j].y;
   g[x]+=f[y];
  }
 }
 SPFA();
 printf("%lld\n",f[1]);
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值