题意看了好久才明白,圣诞树是一个树形结构,对于每条边,它的子孙节点等于这条边中深度较低的那个点的所有子孙节点。本题中一条边的费用就是这条边的所有子孙节点重量和乘上这条边的单位费用。
换一个角度考虑,考虑每个节点会被哪些边包括,答案就是从这个节点到根节点路径上的所有边。这样把每条边的单位费用当作权值,对每个点求一个最短路,答案就是每个点的重量乘上该点最短路的权值在做和。注意No Answer的情况。
代码:
#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
#include <queue>
#include <vector>
#define LL long long
const LL INF= 1e15;
bool vis[50005];
LL d[50005];
int a[50005];
struct edge{
int s,t,c;
edge(){}
edge(int ss,int tt,int cc):s(ss),t(tt),c(cc){}
};
int N,M;
vector<edge> E;
vector<int> G[50005];
void init(){
for(int i=0;i<=N;i++){
d[i]=INF;
G[i].clear();
vis[i]=0;
}
E.clear();
}
void addedge(int s,int t,int c){
E.push_back(edge(s,t,c));
G[s].push_back(E.size()-1);
}
void SPFA(){
queue<int> Q;
while(!Q.empty()) Q.pop();
Q.push(1);
vis[1]=1;
d[1]=0;
while(!Q.empty()){
int cur=Q.front();Q.pop();
vis[cur]=0;
for(int i=0;i<G[cur].size();i++){
edge &tmp=E[G[cur][i]];
if(d[tmp.t]>d[cur]+tmp.c){
d[tmp.t]=d[cur]+tmp.c;
if(!vis[tmp.t]){
vis[tmp.t]=1;
Q.push(tmp.t);
}
}
}
}
}
int main(){
int T;
scanf("%d",&T);
while(T--){
scanf("%d%d",&N,&M);
init();
for(int i=1;i<=N;i++){
scanf("%d",&a[i]);
}
for(int i=1;i<=M;i++){
int s,t,c;
scanf("%d%d%d",&s,&t,&c);
addedge(s,t,c);
addedge(t,s,c);
}
SPFA();
bool ok=1;
LL res=0;
for(int i=1;i<=N;i++){
if(d[i]==INF){
ok=0;
break;
}
res+=d[i]*a[i];
}
if(!ok) printf("No Answer\n");
else printf("%lld\n",res);
}
return 0;
}