比赛场上是暴力怼过去的,回来补题学了个优先队列的想法
因为宝石的合成情况可能有嵌套,比如1和2生成3,1和3生成2,2和3生成1,如果用dp去做的话,那么就会形成一个回路,就没办法当做树形dp搞了
所以我们要想到,如果出现了某个生成环,那么其环三个元素中,魔力值最小的那个一定不可被更新,所以这个环本质上是不影响我们最终最优值的
因此,我们只需要构造一个优先队列,按照所有宝石的魔力值从小到大排序,依次出队列依次对其他点进行更新即可
#include<bits/stdc++.h>
using namespace std;
const int maxn=1e5+500;
struct node{
int value,id;
friend bool operator < (const node &a,const node &b){
return a.value < b.value;
}
}a[maxn];
priority_queue<node> q;
struct Edge{
int a,b,c,nxt;
}edge[maxn*2];
int head[maxn],tot;
int T,n,m;
int dp[maxn];
void addedge(int a,int b,int c){
edge[tot].a=a;
edge[tot].b=b;
edge[tot].c=c;
edge[tot].nxt=head[a];
head[a]=tot++;
}
int main(){
scanf("%d",&T);
while(T--){
while(!q.empty()) q.pop();
scanf("%d%d",&n,&m);
memset(head,-1,sizeof(head));
tot=0;
for(int i=1;i<=n;i++){
scanf("%d",&a[i].value);
a[i].id=i;
q.push(a[i]);
dp[i]=a[i].value;
}
int x,y,z;
while(m--){
scanf("%d%d%d",&x,&y,&z);
addedge(x,y,z);
addedge(y,x,z);
}
while(!q.empty()){
node t=q.top();
int u=t.id;
q.pop();
for(int i=head[u];i!=-1;i=edge[i].nxt){
int v=edge[i].b;
int w=edge[i].c;
if (dp[u]+dp[v]<dp[w]){
dp[w]=dp[u]+dp[v];
node tp;
tp.id=w;
tp.value=dp[w];
q.push(tp);
}
}
}
for(int i=1;i<=n;i++)
printf("%d%c",dp[i],i==n?'\n':' ');
}
return 0;
}