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('\n'); 75 else flag=1; 76 scanf("%d",&q); 77 while(q--){ 78 scanf("%d%d%d",&a,&b,&c); 79 printf("%d\n",calc(a,b)+calc(b,c)+calc(a,c)>>1); 80 } 81 } 82 return 0; 83 }