bzoj3875

来源:互联网 发布:录音电话软件 编辑:程序博客网 时间:2024/04/28 16:11

用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