Problem A 表演

有$n$个有点权的点,$m$个有边权的边。对于每个点$u$,输出从这个点出发到$v$,其路径权值的两倍加上v的点权和最小的值。

对于$100\%$的数据,满足$1 \leq n,m \leq 2\times 10^5 $

Solution : 

  考虑一个简单的转移,$f[u]$表示点$u$的最小答案,最初$f[u]$ 为$u$的点权。

  每一次更新,就是相邻的两个点$u,v$之间,用边权的两倍来更新答案。

  如果在图上DP,那么就相当于,将初始这些点权加入priority_queue,跑最短路即可。

  时间复杂度为$O(m log_2 n)$

# include <bits/stdc++.h>
# define int long long
using namespace std;
const int N=2e5+10;
struct rec{ int pre,to,w;}a[N<<1];
int n,m,tot;
bool inq[N];
int head[N],d[N],val[N];
namespace Fast_IO {
    inline int read() {
        int x=0,w=0; char c=0;
        while (c<'0'||c>'9') w|=c=='-',c=getchar();
        while (c>='0' && c<='9') x=(x<<1)+(x<<3)+(c^48),c=getchar();
        return w?-x:x;
    }
    void write(int x) {
        if (x<0) x=-x,putchar('-');
        if (x>9) write(x/10);
        putchar('0'+x%10);
    }
    void writeln(int x) {
        write(x); putchar('\n');
    }
};
using namespace Fast_IO;
void adde(int u,int v,int w) {
    a[++tot].pre=head[u];
    a[tot].to=v;
    a[tot].w=w*2;
    head[u]=tot;
}
struct Node {
    int id,val;
};
struct cmp {
    bool operator () (Node a,Node b) {
        return a.val > b.val;   
    }
};
priority_queue<Node,vector<Node>,cmp>q;
void dijkstra() {
    for (int i=1;i<=n;i++) {
        d[i]=val[i];
        inq[i]=true;
        q.push((Node){i,val[i]});
    }
    while (q.size()) {
        int u=q.top().id; q.pop(); inq[u]=false;
        for (int i=head[u];i;i=a[i].pre) {
            int v=a[i].to; 
            if (d[v]>d[u]+a[i].w) {
                d[v]=d[u]+a[i].w;
                if (!inq[v]) q.push((Node){v,d[v]}); 
            }
        }
    }
}
signed main() {
    n=read();m=read(); 
    for (int i=1;i<=m;i++) {
        int u=read(),v=read(),w=read();
        adde(u,v,w); adde(v,u,w);
    }
    for (int i=1;i<=n;i++) val[i]=read();
    dijkstra();
    for (int i=1;i<n;i++) write(d[i]),putchar(' ');
    writeln(d[n]);
    return 0;
}
exciting.cpp

相关文章: