思路:用两个数组维护到达某个点的最小大路距离和最小小路距离,注意结果中间过程可能爆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;
}