ZOJ3195 Design the city(LCA)

时间:2023-03-08 16:14:32

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

分几种情况。。三个点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))。。

 #include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
#define MAXN 55555 struct Edge{
int v,w,next;
}edge[MAXN<<];
int NE,head[MAXN];
void addEdge(int u,int v,int w){
edge[NE].v=v; edge[NE].w=w; edge[NE].next=head[u];
head[u]=NE++;
} int dep[MAXN],weight[MAXN],par[][MAXN];
void dfs(int u,int fa,int w){
weight[u]=w;
for(int i=head[u]; i!=-; i=edge[i].next){
int v=edge[i].v;
if(v==fa) continue;
dep[v]=dep[u]+;
par[][v]=u;
dfs(v,u,w+edge[i].w);
}
} void init(int n){
dfs(,,);
for(int i=; i<; ++i){
for(int j=; j<n; ++j){
if(par[i-][j]==-) continue;
par[i][j]=par[i-][par[i-][j]];
}
}
} int lca(int u,int v){
if(dep[u]>dep[v]) swap(u,v);
for(int k=; k<; ++k){
if(dep[v]-dep[u]>>k&){
v=par[k][v];
}
}
if(v==u) return u;
for(int k=; k>=; --k){
if(par[k][u]!=par[k][v]){
u=par[k][u];
v=par[k][v];
}
}
return par[][u];
} int calc(int u,int v){
return weight[u]+weight[v]-*weight[lca(u,v)];
} int main(){
int n,q,a,b,c;
bool flag=;
while(~scanf("%d",&n)){
NE=;
memset(head,-,sizeof(head));
for(int i=; i<n; ++i){
scanf("%d%d%d",&a,&b,&c);
addEdge(a,b,c);
addEdge(b,a,c);
} memset(par,-,sizeof(par));
init(n); if(flag) putchar('\n');
else flag=;
scanf("%d",&q);
while(q--){
scanf("%d%d%d",&a,&b,&c);
printf("%d\n",calc(a,b)+calc(b,c)+calc(a,c)>>);
}
}
return ;
}