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是求两个点的最短路,而该题稍微变形,要求三个点

    所以我们可以两两求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 }

 

转载于:https://www.cnblogs.com/JVxie/p/4933535.html

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值