题目大意:给出一个图,保证两点之间有且仅有一条边连接,求亮点之间的距离。
思路:将图转化为树,然后求最近公共祖先(LCA)。Tarjan算法,图用前向星存储。
开始几次把数组开小了,然后错了好多次。也发现了一个问题,当数组开小了的时候,在杭电上面用G++提交时WA,用C++提交时RE。
代码如下:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<vector>
#include<stack>
using namespace std;
const int maxn=40005;
int first[maxn];
int tot;
int ancestor[maxn];
int check[maxn];
int weight[maxn];
int n,m;
struct Edge{
int u,v,next;
int w;
}edge[maxn*2];
struct question{
int u,v,ans;
}queries[maxn];
void addedge(int u,int v,int w){
edge[tot].u=u;
edge[tot].v=v;
edge[tot].w=w;
edge[tot].next=first[u];
first[u]=tot++;
}
int findset(int u){
if(u!=ancestor[u])ancestor[u]=findset(ancestor[u]);
return ancestor[u];
}
void unionset(int a,int b){
b=findset(b);
a=findset(a);
ancestor[b]=ancestor[a];
}
void lca(int u)
{
ancestor[u]=u;
check[u]=true;
for(int i=0;i<m;++i){
int &x=queries[i].u;
int &y=queries[i].v;
int &z=queries[i].ans;
if(x==u&&check[y])z=findset(y);
if(y==u&&check[x])z=findset(x);
}
for(int i=first[u];i!=-1;i=edge[i].next){
int v=edge[i].v;
if(check[v])continue;
weight[v]=weight[u]+edge[i].w;
lca(v);
ancestor[v]=u;
}
}
int main(){
// freopen("data.txt","r",stdin);
int T;
scanf("%d",&T);
while(T--){
tot=0;
memset(first,-1,sizeof(first));
memset(check,0,sizeof(check));
for(int i=0;i<maxn;++i){
edge[i].next=-1;
}
for(int i=0;i<=n;++i){
ancestor[i]=i;
}
weight[1]=0;
//³õʼ»¯
scanf("%d%d",&n,&m);
for(int i=0;i<n-1;++i){
int ii,jj,kk;
scanf("%d%d%d",&ii,&jj,&kk);
addedge(ii,jj,kk);
addedge(jj,ii,kk);
}
for(int i=0;i<m;++i){
int u,v;
scanf("%d%d",&u,&v);
queries[i].u=u;
queries[i].v=v;
}
lca(1);
int rec=0;
for(int i=0;i<m;++i){
rec++;
int &u=queries[i].u;
int &v=queries[i].v;
int &p=queries[i].ans;
printf("%d\n",weight[u]+weight[v]-2*weight[p]);
}
while(rec!=m);
// printf("\n");
}
return 0;
}