题目链接


比赛场上是暴力怼过去的,回来补题学了个优先队列的想法

因为宝石的合成情况可能有嵌套,比如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;
}