思路:用两个数组维护到达某个点的最小大路距离和最小小路距离,注意结果中间过程可能爆int, 不加long long 只有70分。
有一种特殊情况就是通过走两次大路,消除连续的小路值,这里就是用两个数组维护的原因。
#include <bits/stdc++.h> using namespace std; const int MAXN = 100005; typedef long long LL; int n,m; struct Edge { int to,from, t; LL w; } edge[2*MAXN]; struct node { int u; LL d1,d2; }; LL dist1[MAXN],dist2[MAXN]; int head[2*MAXN]; int cnt; void add(int t, int u, int v, LL w) { edge[cnt].to=v; edge[cnt].w=w; edge[cnt].t=t; edge[cnt].from=head[u]; head[u]=cnt++; } void spfa(int s) { queue<node> q; while(!q.empty()) q.pop(); memset(dist1,-1,sizeof(dist1)); memset(dist2,-1,sizeof(dist2)); dist1[1]=dist2[1]=0; q.push((node) { s,0,0 }); while(!q.empty()) { node u=q.front(); q.pop(); for(int i=head[u.u]; ~i; i=edge[i].from) { Edge v=edge[i]; if(v.t==0) { if(dist1[v.to]==-1||dist1[v.to]>=u.d1+v.w+u.d2*u.d2) { dist1[v.to]=u.d1+v.w+u.d2*u.d2; q.push((node) { v.to,u.d1+v.w+u.d2*u.d2,0 }); } } else { if(dist2[v.to]==-1||dist2[v.to]>=u.d1+(v.w+u.d2)*(v.w+u.d2)) { dist2[v.to]=u.d1+(v.w+u.d2)*(v.w+u.d2); q.push((node) { v.to,u.d1,u.d2+v.w }); } } } } //for(int i=1; i<=n; ++i) //printf("%d dist1[%d]=%d dist2[%d]=%d\n", i, i, dist1[i], i, dist2[i]); if(dist1[n]==-1) printf("%lld\n", dist2[n]); else if(dist2[n]==-1) printf("%lld\n", dist1[n]); else printf("%lld\n", min(dist1[n],dist2[n])); } int main() { cnt=0; memset(head,-1,sizeof(head)); scanf("%d %d", &n,&m); for(int i=1; i<=m; ++i) { int t, a, b; LL c; scanf("%d %d %d %lld", &t, &a, &b, &c); add(t,a,b,c); add(t,b,a,c); } spfa(1); return 0; }