[NOI2014]魔法森林[最短路 spfa]
[NOI2014]魔法森林
一条边有\(a_i,b_i\)两个权值 求\(1->n\)路径上\(a\)的最大值与\(b\)的最大值之和的最小
==有lct的做法 但是spfa动态加点的做法也很巧妙!
先将其按\(a\)从小到大排序 然后依次加入边
对于ans的每次更新 当ans第一次更新时说明在加入这条边后才存在\(1->n\)的路 而新加的这条边一定在\(1->n\)的路径上
之后的更新也差不多同理(寄几想一想为什么
每加入一条边 就只用从新加入的这条边的\(u,v\)来开始更新 不用跑完==
int dis[N],vis[N];
queue<int> q;
void spfa(int a,int b){
vis[a]=vis[b]=1;
q.push(a),q.push(b);
while(!q.empty()){
int u=q.front();q.pop(),vis[u]=0;
for(int i=head[u],v,w;i;i=e[i].nxt)
if(dis[v=e[i].v]>Max(dis[u],w=e[i].w)){
dis[v]=Max(dis[u],e[i].w);
if(!vis[v]) q.push(v),vis[v]=1;
}
}
}
int main(){
#ifndef ONLINE_JUDGE
// freopen("in.txt","r",stdin);
#endif
rd(n),rd(m);ans=inf;
memset(dis,inf,sizeof(dis));
for(int i=1,u,v,a,b;i<=m;++i) rd(u),rd(v),rd(a),rd(b),E[i]=(node){u,v,a,b};
sort(E+1,E+m+1,cmp);
dis[1]=0;
for(int i=1,u,v,w;i<=m;++i){
u=E[i].u,v=E[i].v,w=E[i].b;
add(u,v,w),add(v,u,w);
spfa(u,v);
ans=Min(ans,dis[n]+E[i].a);
}
if(ans==inf) return puts("-1"),0;
printf("%d",ans);
return 0;
}