[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;
}
posted @ 2019-10-13 20:38  委屈的咸鱼鱼鱼鱼  阅读(138)  评论(0编辑  收藏  举报