zoukankan      html  css  js  c++  java
  • [bzoj1880] P2149 [SDOI2009]Elaxia的路线

    https://www.luogu.com.cn/problem/P2149
    https://darkbzoj.tk/problem/1880
    最近bzoj又不能上了,估计以后可能还没有dbzoj活得长

    最短路+建出最短路经过的DAG并拓扑排序


    (1le nle 1500,1le wle 10^4)


    一开始想暴力把每两个点的最短路用dij跑出来,然后枚举两个点判断(为什么可以直接枚举两个点在下面会说),结果发现边数没有要求,边数稍微多点就T,只有55

    边权为正,最短路肯定没环,那么如果把所有 (s)(t) 的最短路中,可能经过(因为最短路可能有多条)的边选出来,建一个新图,那么新图是个DAG
    那么如何建这个DAG?分别以 (s,t) 为源点,跑两个dij,然后枚举每一条边 ((u,v))
    (dis_{i,j}) 表示以 (i) 为源点,(j) 的最短路,如果 (dis_{s,u}+w_{u,v}+dis_{t,v}=dis_{s,t}),显然就可以选这个边

    又有一个结论:它们两个走的最长公共路径,一定是一条链
    因为假设公共路径是从一个点分开,再从前方另一个点汇合,那么肯定说明这样走会让其中一方走的最短路更段
    但又因为前面还会汇合,就可以让另一方也走这一方的路径(最短路总长度也会更短),所以这个路径还是一条链,矛盾

    所以,我们以 (x1,x2,y1,y2) 分别跑最短路,然后枚举边
    当边 ((u,v)) 同时满足 (dis_{x1,u}+w_{u,v}+dis_{y1,v}=dis_{x1,y1})(dis_{x2,u}+w_{u,v}+dis_{y2,v}=dis_{x2,y2}),就选这个边,建DAG
    然后拓扑排序找最长链就行了

    但是,这只是其中一种情况,也就是它们“并行”一段路,其实还有一种情况是它们“相遇”,也就是最短路重合,但是方向不同
    虽然这不符合题目背景,但是:

    毕竟题目描述只是给个背景,认真你就输了

    所以还要反着判断建一个DAG,拓扑跑两遍

    #include<cstdio>
    #include<algorithm>
    #include<iostream>
    #include<cmath>
    #include<map>
    #include<iomanip>
    #include<cstring>
    #include<vector>
    #include<queue>
    #define reg register
    #define EN std::puts("")
    #define LL long long
    inline int read(){
    	register int x=0;register int y=1;
    	register char c=std::getchar();
    	while(c<'0'||c>'9'){if(c=='-') y=0;c=std::getchar();}
    	while(c>='0'&&c<='9'){x=x*10+(c^48);c=std::getchar();}
    	return y?x:-x;
    }
    #define N 1505
    #define M 2500006
    struct graph{
    	int fir[N],nex[M],to[M],w[M],tot;
    	inline void add(int u,int v,int z){
    		to[++tot]=v;w[tot]=z;
    		nex[tot]=fir[u];fir[u]=tot;
    	}
    }G,D;
    int x1,x2,y1_,y2,n,m;
    int in[N],heap[N],size;
    int disx1[N],disy1[N],disx2[N],disy2[N];
    int len[N];
    int indeg[N],que[N],tail,head;
    inline void push(int x,int dis[]){
    	heap[++size]=x;
    	reg int i=size,fa;
    	while(i>1){
    		fa=i>>1;
    		if(dis[heap[fa]]<=dis[heap[i]]) return;
    		std::swap(heap[fa],heap[i]);i=fa;
    	}
    }
    inline int pop(int dis[]){
    	int ret=heap[1];heap[1]=heap[size--];
    	int i=1,ls,rs;
    	while((i<<1)<=size){
    		ls=i<<1;rs=ls|1;
    		if(rs<=size&&dis[heap[rs]]<=dis[heap[ls]]) ls=rs;
    		if(dis[heap[ls]]>=dis[heap[i]]) break;
    		std::swap(heap[i],heap[ls]);i=ls;
    	}
    	return ret;
    }
    inline void dij(int start,int dis[]){
    	std::memset(dis,0x3f,(n+1)*sizeof dis[0]);dis[start]=0;
    	push(start,dis);
    	while(size){
    		reg int u=pop(dis),v;in[u]=0;
    		for(reg int i=G.fir[u];i;i=G.nex[i]){
    			v=G.to[i];
    			if(dis[v]>dis[u]+G.w[i]){
    				dis[v]=dis[u]+G.w[i];
    				if(!in[v]) push(v,dis),in[v]=1;
    			}
    		}
    	}
    }
    inline void topo(){
    	tail=0;head=-1;
    	reg int u,v;
    	for(reg int i=1;i<=n;i++)if(!indeg[i]) que[++head]=i;
    	while(tail<=head){
    		u=que[tail++];
    		for(reg int i=D.fir[u];i;i=D.nex[i]){
    			v=D.to[i];
    			len[v]=std::max(len[v],len[u]+D.w[i]);
    			if(!--indeg[v]) que[++head]=v;
    		}
    	}
    }
    inline void do_topo(){
    	for(reg int i=1;i<=n;i++)for(reg int j=G.fir[i];j;j=G.nex[j])
    		if(disx1[i]+G.w[j]+disy1[G.to[j]]==disx1[y1_]&&disx2[i]+G.w[j]+disy2[G.to[j]]==disx2[y2])
    			D.add(i,G.to[j],G.w[j]),indeg[G.to[j]]++;
    	topo();
    	std::memset(D.fir,0,sizeof D.fir);std::memset(D.nex,0,sizeof D.nex);
    	D.tot=0;
    	std::memset(indeg,0,sizeof indeg);
    	for(reg int i=1;i<=n;i++)for(reg int j=G.fir[i];j;j=G.nex[j])
    		if(disx1[i]+G.w[j]+disy1[G.to[j]]==disx1[y1_]&&disy2[i]+G.w[j]+disx2[G.to[j]]==disx2[y2])
    			D.add(i,G.to[j],G.w[j]),indeg[G.to[j]]++;
    	topo();
    }
    int main(){
    	n=read();m=read();
    	x1=read();y1_=read();x2=read();y2=read();
    	for(reg int u,v,z,i=1;i<=m;i++){
    		u=read();v=read();z=read();
    		G.add(u,v,z);G.add(v,u,z);
    	}
    	dij(x1,disx1);dij(y1_,disy1);dij(x2,disx2);dij(y2,disy2);
    	do_topo();
    	reg int ans=0;
    	for(reg int i=1;i<=n;i++) ans=std::max(ans,len[i]);
    	std::printf("%d",ans);
    	return 0;
    }
    
  • 相关阅读:
    轻松掌握Ajax.net系列教程十二:使用TabContainer&TabPanel
    轻松掌握Ajax.net系列教程十五:使用AutoCompleteExtender
    一步一步学Linq to sql(二):DataContext与实体
    一步一步学Linq to sql(十):分层构架的例子
    轻松掌握Ajax.net系列教程十四:使用CalendarExtender
    一步一步学Linq to sql(八):继承与关系
    整理了一些tsql技巧
    一步一步学Linq to sql(三):增删改
    数据库连接字符串大全
    海量数据库的查询优化及分页算法方案
  • 原文地址:https://www.cnblogs.com/suxxsfe/p/12896329.html
Copyright © 2011-2022 走看看