给一颗无向树有n个结点,有m个询问,问树上任意两点间距离,n的范围是40000,m是200
这题告诉我们一个求树上两点间距离的好方法,就是先求根到其余所有点的距离,再求出询问的LCA,答案为dis[a]+dis[b]-2*dis[lca(a,b)]
#include <iostream>
#include <cstdlib>
#include <cstring>
#include <string>
#include <cstdio>
#include <cmath>
#include <algorithm>
#include <vector>
#include <queue>
#include <map>
#define inf 0x3f3f3f3f
#pragma comment(linker, "/STACK:16777216")
#define eps 1e-6
#define ll long long
using namespace std;
const int maxn=40010;
int dis[maxn];
struct node
{
int v,id,w;//id为边号或询问号
node* next;
}ed[maxn<<2],*head[maxn],*q[maxn];
struct qnode
{
int u,v,ans;//存询问结点,ans最近公共祖先
} qu[maxn];
int fa[maxn],vis[maxn],cnt;
void init(int n)
{
cnt=0;
memset(vis,0,sizeof vis);
memset(head,0,sizeof head);
memset(q,0,sizeof q);
for(int i=0;i<=n;i++)
fa[i]=i;
}
int getfa(int x)
{
if(fa[x]==x) return x;
return fa[x]=getfa(fa[x]);
}
void LCA(int u)
{
fa[u]=u,vis[u]=1;
for(node *p=q[u];p!=NULL;p=p->next)
{
if(vis[p->v])
{
int id=p->id;
qu[id].ans=getfa(p->v);
}
}
for(node *p=head[u];p!=NULL;p=p->next)
{
if(!vis[p->v])
{
LCA(p->v);
fa[p->v]=u;
}
}
}
void adde(node *e[],int u,int v,int w,int id)//建边e传头节点数组。为询问边的或树边的。
{
ed[cnt].v=v;
ed[cnt].w=w;
ed[cnt].id=id;
ed[cnt].next=e[u];
e[u]=&ed[cnt++];
}
void dfs(int s,int d)
{
for(node *p=head[s];p!=NULL;p=p->next)
{
if(!vis[p->v])
{
vis[p->v]=1;
dis[p->v]=d+(p->w);
dfs(p->v,dis[p->v]);
}
}
}
int main()
{
int icy,a,b,c,i,m,n;
scanf("%d",&icy);
while(icy--)
{
scanf("%d%d",&n,&m);
init(n);
for(i=1;i<=n-1;i++)
{
scanf("%d%d%d",&a,&b,&c);
adde(head,a,b,c,i);
adde(head,b,a,c,i);
}
for(i=1;i<=m;i++)
{
scanf("%d%d",&a,&b);
adde(q,a,b,0,i);
adde(q,b,a,0,i);
qu[i].u=a;
qu[i].v=b;
}
LCA(1);
memset(dis,0,sizeof dis);
memset(vis,0,sizeof vis);
vis[1]=1;dis[1]=0;
dfs(1,0);
for(i=1;i<=m;i++)
printf("%d\n",dis[qu[i].u]+dis[qu[i].v]-dis[qu[i].ans]-dis[qu[i].ans]);
}
return 0;
}