首页 > 代码库 > [HDU2874]Connections between cities

[HDU2874]Connections between cities

题目大意:给你n个节点的森林(注意不是一棵树),m条路径的长度,c个询问,要你回答每个询问两个点i和j的最短距离,或者回答没有连接。

数据范围:2<=n<=10000,0<=m<10000,1<=c<=1000000

解题思路:对于每个节点,求出其到根的距离a[i],然后求两点的最近公共祖先LCA,最后的答案为$a[i]+a[j]-2*a[LCA(i,j)]$。

我用的是Tarjan算法。

注意此题可能出现两个相同点的情况,需要注意一些细节,或者特判。

C++ Code:

 

#include<cstdio>#include<cstring>using namespace std;int n,m,c,cnt=0,cntq=0,head[10002],headq[1000002],fa[10002],a[10002]={0};bool vis[10002],all[10002];struct edge{	int to,dist,next;}e[20004];struct Q{	int to,next;}q[2000004];int ans[1000002];void addedge(int from,int to,int dist){	cnt++;	e[cnt].to=to;	e[cnt].dist=dist;	e[cnt].next=head[from];	head[from]=cnt;	cnt++;	e[cnt].to=from;	e[cnt].dist=dist;	e[cnt].next=head[to];	head[to]=cnt;}int dad(int x){	return(fa[x]==x)?(x):(fa[x]=dad(fa[x]));}void addq(int x,int y){	cntq++;	q[cntq].to=y;	q[cntq].next=headq[x];	headq[x]=cntq;	cntq++;	q[cntq].to=x;	q[cntq].next=headq[y];	headq[y]=cntq;}void lca(int root,int pre){	fa[root]=root;	for(int i=head[root];i;i=e[i].next){		int p=e[i].to;		if(p!=pre){			a[p]=a[root]+e[i].dist;			lca(p,root);		}	}	vis[root]=all[root]=true;	for(int i=headq[root];i;i=q[i].next){		int p=q[i].to;		if(vis[p]){			int LCA=dad(p);			ans[(i+1)/2]=a[root]+a[p]-a[LCA]*2;		}	}	fa[root]=pre;}int main(){	while(scanf("%d%d%d",&n,&m,&c)!=EOF){		cnt=cntq=0;		memset(a,0,sizeof(a));		memset(fa,0,sizeof(fa));		memset(head,0,sizeof(head));		memset(headq,0,sizeof(headq));		memset(e,0,sizeof(e));		memset(q,0,sizeof(q));		memset(ans,-1,sizeof(ans));		memset(all,0,sizeof(all));		for(int i=1;i<=m;i++){			int from,to,dist;			scanf("%d%d%d",&from,&to,&dist);			addedge(from,to,dist);		}		for(int i=1;i<=c;i++){			int x,y;			scanf("%d%d",&x,&y);			addq(x,y);		}		for(int i=1;i<=n;i++)		if(!all[i]){			memset(vis,0,sizeof(vis));			lca(i,0);		}		for(int i=1;i<=c;i++)		if(ans[i]==-1)puts("Not connected");else		printf("%d\n",ans[i]);	}	return 0;}

 

  

 

[HDU2874]Connections between cities