ZOJ 3195 Design the city 题解
这个题目大意是:
有N个城市,编号为0~N-1,给定N-1条无向带权边,Q个询问,每个询问求三个城市连起来的最小权值。
多组数据 每组数据 1 < N < 50000 1 < Q < 70000;
一道多源最短路的题目,注意题目数据:N、Q都很大
不能考虑Floyd、SPFA、Dijkstra、Bellman-Ford等最短路算法
再看N-1条边,明显构成一棵树,最短路有且只有一条
很明显需要LCA....
我们所熟知的LCA是求两个点的最短路,而该题稍微变形,要求三个点
所以我们可以两两求LCA,然后把三个dist值加起来除以二
而两点的dist值是这样算的:dist[a]+dist[b]-2*dist[LCA(a,b)]
代码如下:
1 #include <cstdio> 2 #include <cstring> 3 #include <iostream> 4 #include <algorithm> 5 #define N 200010 6 #define M 600010 7 using namespace std; 8 struct DATA 9 { 10 int from,to,dis,next,i; 11 }road[N],ques[M]; 12 int dist[N],head1[N],head2[M],f[N],ans[M],n,q,len1,len2,fun=0; 13 bool vis[N],book[M],found[N]; 14 void add1(int a,int b,int c,int i) 15 { 16 len1++; 17 road[len1].from=a; 18 road[len1].to=b; 19 road[len1].dis=c; 20 road[len1].i=i; 21 road[len1].next=head1[a]; 22 head1[a]=len1; 23 } 24 void add2(int a,int b,int c,int i) 25 { 26 len2++; 27 ques[len2].from=a; 28 ques[len2].to=b; 29 ques[len2].dis=c; 30 ques[len2].i=i; 31 ques[len2].next=head2[a]; 32 head2[a]=len2; 33 } 34 int find(int x){return f[x]==x?x:f[x]=find(f[x]);} 35 void marge(int x,int y){if(find(x)!=find(y)) f[y]=x;} 36 void Tarjan(int u,int dev) 37 { 38 int e=head1[u],a,b,i,tmp; 39 while(e!=-1) 40 { 41 a=road[e].to; 42 i=road[e].i; 43 tmp=dev+road[e].dis; 44 if(!vis[a] && !found[i]) 45 { 46 found[i]=1; 47 dist[a]=tmp; 48 Tarjan(a,tmp); 49 vis[a]=1; 50 marge(u,a); 51 } 52 e=road[e].next; 53 } 54 e=head2[u]; 55 while(e!=-1) 56 { 57 a=ques[e].to; 58 i=ques[e].i; 59 if(vis[a] && !book[i]) 60 { 61 book[i]=1; 62 b=find(a); 63 ans[i]=dist[a]+dist[u]-2*dist[b]; 64 } 65 e=ques[e].next; 66 } 67 return ; 68 } 69 void init() 70 { 71 int i; 72 len1=0,len2=0; 73 for(i=0;i<N;i++) 74 { 75 road[i].from=road[i].to=road[i].dis=road[i].next=road[i].i=0; 76 f[i]=i; 77 } 78 for(i=0;i<M;i++) 79 ques[i].from=ques[i].to=ques[i].dis=ques[i].next=ques[i].i=0; 80 memset(head1,-1,sizeof(head1)); 81 memset(head2,-1,sizeof(head2)); 82 memset(dist,0,sizeof(dist)); 83 memset(vis,0,sizeof(vis)); 84 memset(book,0,sizeof(book)); 85 memset(found,0,sizeof(found)); 86 memset(ans,0,sizeof(ans)); 87 return ; 88 } 89 int main() 90 { 91 // freopen("1.in","r",stdin); 92 // freopen("test.out","w",stdout); 93 while(~scanf("%d",&n)) 94 { 95 if(fun++) printf("\n"); 96 init(); 97 int i,a,b,c,tmp=99999999; 98 for(i=1;i<n;i++) 99 { 100 scanf("%d%d%d",&a,&b,&c); 101 add1(a,b,c,i); 102 add1(b,a,c,i); 103 tmp=min(min(a,b),tmp); 104 } 105 scanf("%d",&q); 106 for(i=1;i<=q;i++) 107 { 108 scanf("%d%d%d",&a,&b,&c); 109 add2(a,b,0,i); 110 add2(b,a,0,i); 111 add2(a,c,0,i+q); 112 add2(c,a,0,i+q); 113 add2(b,c,0,i+2*q); 114 add2(c,b,0,i+2*q); 115 } 116 Tarjan(tmp,0); 117 for(i=1;i<=q;i++) 118 printf("%d\n",(ans[i]+ans[i+q]+ans[i+2*q])/2); 119 } 120 return 0; 121 }