北方大学多校联合训练第十一场E:Modules
题目链接:http://112.74.33.53/contest/10/problem/58/
题目大意:有$1$块主板和$n$个增强模块,增强模块可以加在主板或者其他连在主板上的模块上为其带来$p[i]$的增益,当模块$a[i]$连在模块$b[i]$上时,可以带来额外$q[i]$的增益,问最大增益是多少.
最小树形图
不考虑额外增益的情况下,将模块连到模块上的效果与直接连到主板上是一致的,故只需从主板向各个模块连边;考虑额外增益,只需从$b[i]$向$a[i]$额外建边.
代码如下:
1 #include <cstdio> 2 #include <cstring> 3 #define MAXN 3005 4 #define MAXM 6005 5 using namespace std; 6 typedef long long ll; 7 const ll inf=1000000000000000; 8 ll T,n,m,p[MAXN],a,b,q; 9 struct ZL{ 10 ll n,m; 11 ll pre[MAXN],id[MAXN],vis[MAXN]; 12 ll inEdge[MAXN]; 13 struct Edge{ 14 ll u,v; 15 ll w; 16 }edge[MAXM]; 17 void init(ll n_){ 18 n=n_;m=0; 19 } 20 void addedge(ll u,ll v,ll w){ 21 edge[m].u=u; 22 edge[m].v=v; 23 edge[m].w=w; 24 m++; 25 } 26 ll Directed_MST(ll root){ 27 ll ans=0,u,v; 28 while(1){ 29 for(ll i=0;i<n;++i) 30 inEdge[i]=inf; 31 for(ll i=0;i<m;++i){ 32 u=edge[i].u; 33 v=edge[i].v; 34 if(edge[i].w<inEdge[v]&&u!=v) { 35 pre[v]=u; 36 inEdge[v]=edge[i].w; 37 } 38 } 39 for(ll i=0;i<n;++i) 40 if(i!=root&&inEdge[i]==inf) 41 return -1; 42 ll cnt=0; 43 memset(id,-1,sizeof(id)); 44 memset(vis,-1,sizeof(vis)); 45 inEdge[root]=0; 46 for(ll i=0;i<n;++i) { 47 ans+=inEdge[i]; 48 ll cur=i; 49 while(vis[cur]!=i&&cur!=root&&id[cur]==-1) { 50 vis[cur]=i; 51 cur=pre[cur]; 52 } 53 if(cur!=root&&id[cur]==-1) { 54 v=pre[cur]; 55 while(v!=cur) { 56 id[v]=cnt; 57 v=pre[v]; 58 } 59 id[cur]=cnt++; 60 } 61 } 62 if(cnt==0)return ans; 63 for(int i=0;i<n;++i) 64 if(id[i]==-1) 65 id[i]=cnt++; 66 for(int i=0;i<m;++i) { 67 u=edge[i].u; 68 v=edge[i].v; 69 edge[i].u=id[u]; 70 edge[i].v=id[v]; 71 if(id[u]!=id[v]) 72 edge[i].w-=inEdge[v]; 73 } 74 n=cnt; 75 root=id[root]; 76 } 77 return ans; 78 } 79 }gao; 80 int main(void){ 81 scanf("%lld",&T); 82 while(T--){ 83 scanf("%lld%lld",&n,&m); 84 gao.init(n+1); 85 for(int i=1;i<=n;++i){ 86 scanf("%lld",&p[i]); 87 gao.addedge(0,i,-p[i]); 88 } 89 for(int i=0;i<m;++i){ 90 scanf("%lld%lld%lld",&a,&b,&q); 91 gao.addedge(b,a,-q-p[a]); 92 } 93 printf("%lld ",-gao.Directed_MST(0)); 94 } 95 }