题目:https://www.lydsy.com/JudgeOnline/problem.php?id=4289
可以把一个点上的边按权值排序,然后边权小的向第一个比它大的连差值的边,边权大的向第一个比它小的连0边;这样能体现出“边权较大的边的边权”。
别忘了每条边还要自己跟自己连自己权值的边,表示不是差值的初始值。
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #include<vector> #include<queue> #define ll long long using namespace std; const int N=1e5+5,M=2e5+5; int n,m,hd[M<<1],xnt,to[M<<3],nxt[M<<3],w[M<<3]; ll dis[M<<1],ans=0x3f3f3f3f3f3f3f3f;//M<<1!v bool vis[M<<1]; struct Node{ int bh,w;Node(int a=0,int b=0):bh(a),w(b) {} }; vector<Node>e[N]; priority_queue<pair<ll,int> > q; bool cmp(Node u,Node v){return u.w<v.w;} int rdn() { int ret=0;bool fx=1;char ch=getchar(); while(ch>'9'||ch<'0'){if(ch=='-')fx=0;ch=getchar();} while(ch>='0'&&ch<='9') ret=(ret<<3)+(ret<<1)+ch-'0',ch=getchar(); return fx?ret:-ret; } void add(int x,int y,int z) { to[++xnt]=y;nxt[xnt]=hd[x];hd[x]=xnt;w[xnt]=z; } void dj() { while(q.size()) { int k=q.top().second;q.pop(); if(vis[k])continue; vis[k]=1; for(int i=hd[k],v;i;i=nxt[i]) if(dis[v=to[i]]>dis[k]+w[i]) { dis[v]=dis[k]+w[i]; q.push(make_pair(-dis[v],v)); } } } int main() { n=rdn(); m=rdn(); for(int i=1,u,v,z;i<=m;i++) { u=rdn(); v=rdn(); z=rdn(); add(i,i+m,z); add(i+m,i,z); e[u].push_back(Node(i,z)); e[v].push_back(Node(i+m,z)); } for(int i=1;i<=n;i++) { sort(e[i].begin(),e[i].end(),cmp); int d=e[i].size(); for(int j=0;j<d-1;j++) { add(e[i][j].bh,e[i][j+1].bh,e[i][j+1].w-e[i][j].w); add(e[i][j+1].bh,e[i][j].bh,0); } } memset(dis,0x3f,sizeof dis); int d=e[1].size(); for(int i=0;i<d;i++) { dis[e[1][i].bh]=e[1][i].w; q.push(make_pair(-e[1][i].w,e[1][i].bh)); } dj(); d=e[n].size(); for(int i=0;i<d;i++)ans=min(ans,dis[e[n][i].bh]); printf("%lld ",ans); return 0; }