ZOJ3195 Design the city(LCA)

题目大概说给一棵树,每次询问三个点,问要把三个点连在一起的最少边权和是多少。

分几种情况。。三个点LCA都相同,三个点有两对的LCA是某一点,三个点有两对的LCA各不相同。。。%……¥……

画画图可以发现。。虽然好像不太严谨。。连接(a,b,c)三个点的最短边权和=(dist(a,b)+dist(b,c)+dist(a,c))/2,而dist(u,v)的计算可以预处理出各点到根的距离weight,dist(u,v)=weight(u)+weight(v)-2*weight(lca(u,v))。。

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<algorithm>
 4 using namespace std;
 5 #define MAXN 55555
 6 
 7 struct Edge{
 8     int v,w,next;
 9 }edge[MAXN<<1];
10 int NE,head[MAXN];
11 void addEdge(int u,int v,int w){
12     edge[NE].v=v; edge[NE].w=w; edge[NE].next=head[u];
13     head[u]=NE++;
14 }
15 
16 int dep[MAXN],weight[MAXN],par[17][MAXN];
17 void dfs(int u,int fa,int w){
18     weight[u]=w;
19     for(int i=head[u]; i!=-1; i=edge[i].next){
20         int v=edge[i].v;
21         if(v==fa) continue;
22         dep[v]=dep[u]+1;
23         par[0][v]=u;
24         dfs(v,u,w+edge[i].w);
25     }
26 }
27 
28 void init(int n){
29     dfs(0,0,0);
30     for(int i=1; i<17; ++i){
31         for(int j=0; j<n; ++j){
32             if(par[i-1][j]==-1) continue;
33             par[i][j]=par[i-1][par[i-1][j]];
34         }
35     }
36 }
37 
38 int lca(int u,int v){
39     if(dep[u]>dep[v]) swap(u,v);
40     for(int k=0; k<17; ++k){
41         if(dep[v]-dep[u]>>k&1){
42             v=par[k][v];
43         }
44     }
45     if(v==u) return u;
46     for(int k=16; k>=0; --k){
47         if(par[k][u]!=par[k][v]){
48             u=par[k][u];
49             v=par[k][v];
50         }
51     }
52     return par[0][u];
53 }
54 
55 int calc(int u,int v){
56     return weight[u]+weight[v]-2*weight[lca(u,v)];
57 }
58 
59 int main(){
60     int n,q,a,b,c;
61     bool flag=0;
62     while(~scanf("%d",&n)){
63         NE=0;
64         memset(head,-1,sizeof(head));
65         for(int i=1; i<n; ++i){
66             scanf("%d%d%d",&a,&b,&c);
67             addEdge(a,b,c);
68             addEdge(b,a,c);
69         }
70 
71         memset(par,-1,sizeof(par));
72         init(n);
73 
74         if(flag) putchar('
');
75         else flag=1;
76         scanf("%d",&q);
77         while(q--){
78             scanf("%d%d%d",&a,&b,&c);
79             printf("%d
",calc(a,b)+calc(b,c)+calc(a,c)>>1);
80         }
81     }
82     return 0;
83 }
原文地址:https://www.cnblogs.com/WABoss/p/5491998.html