这个题比普通的LCA只多了一个求距离,然后就把我华丽丽的困住了==
当然了,我用的LCA是离线版的并查集那种模板是邝斌的那种,LCA 不难理解,就是dfs树+并查集 ,但是距离加在哪里??
机智如我想到了在递归的时候求~然而写进去还找错位置了,原因在于应该写成dis[v]=dis[u]+edge[i].len;而不是dis[v]+=edge[i].len;
然后就是距离的求法dis[u] + dis[v] - 2 * dis[ans(u, v)]
/********
hdu2586
2015.11.25
46MS 4308K 3383 B C++
********/
#include <iostream>
#include <stdio.h>
#include <algorithm>
#include <string.h>
using namespace std;
const int maxn=40005;//顶点数
const int maxq=205;//最多查询次数,根据题目而定,本题中其实每组数据只有一个查询.
//并查集
int f[maxn];//根节点
int find(int x)
{
if(f[x]==-1)
return x;
return f[x]=find(f[x]);
}
void unite(int u,int v)
{
int x=find(u);
int y=find(v);
if(x!=y)
f[x]=y;
}
//并查集结束
bool vis[maxn];//节点是否访问
int ancestor[maxn];//节点i的祖先
struct Edge
{
int to,next,len;
}edge[maxn*2];
int head[maxn],tot;
void addedge(int u,int v,int length)//邻接表头插法加边
{
edge[tot].to=v;
edge[tot].len=length;
// printf("%d ",length);
edge[tot].next=head[u];
head[u]=tot++;
}
struct Query
{
int q,next;
int index;//查询编号,也就是输入的顺序
}query[maxq*2];
int ans[maxn*2];//存储每次查询的结果,下表0~Q-1,其实应该开maxq大小的。
int h[maxn],tt;
int Q;//题目中需要查询的次数
int dis[maxn];
void addquery(int u,int v,int index)//邻接表头插法加询问
{
query[tt].q=v;
query[tt].next=h[u];
query[tt].index=index;
h[u]=tt++;
query[tt].q=u;//相当于两次查询,比如查询 3,5 和5,3结果是一样的,以3为头节点的邻接表中有5,以5为头节点的邻接表中有3
query[tt].next=h[v];
query[tt].index=index;
h[v]=tt++;
}
void init()
{
tot=0;
memset(head,-1,sizeof(head));
tt=0;
memset(h,-1,sizeof(h));
memset(vis,0,sizeof(vis));
memset(f,-1,sizeof(f));
memset(ancestor,0,sizeof(ancestor));
memset(dis,0,sizeof(dis));
}
void LCA(int u)
{
ancestor[u]=u;
vis[u]=true;
for(int i=head[u];i!=-1;i=edge[i].next)//和顶点u相关的顶点
{
int v=edge[i].to;
// printf("%d ",edge[i].len);
if(vis[v])
continue;
//dis[v]+=edge[i].len;
dis[v]=dis[u]+edge[i].len;
LCA(v);
unite(u,v);
ancestor[find(u)]=u;//将u的左右孩子的祖先设为u
//dis[find(u)]+=dis[u];
}
for(int i=h[u];i!=-1;i=query[i].next)//看输入的查询里面有没有和u节点相关的
{
int v=query[i].q;
if(vis[v])
ans[query[i].index]=ancestor[find(v)];
}
}
bool flag[maxn];//用来确定根节点的
int t;
int n,u,v,len;
int main()
{
int a,b,c;
// freopen("cin.txt","r",stdin);
// scanf("%d(%d):%d",&a,&b,&c);
// cout<<a<<b<<c;
scanf("%d",&t);
while(t--)
{
scanf("%d%d",&n,&Q);
init();
memset(flag,0,sizeof(flag));
for(int i=1;i<n;i++)
{
scanf("%d%d%d",&u,&v,&len);
flag[v]=true;//有入度
addedge(u,v,len);
addedge(v,u,len);
}
for(int i=0;i<Q;i++)
{
scanf("%d%d",&u,&v);
addquery(u,v,i);
}
int root;
for(int i=1;i<=n;i++)
{
if(!flag[i])
{
root=i;
// printf("root=%d ",root);
break;
}
}
LCA(root);
// for(int i=1;i<=n;i++)printf("%d ",dis[i]); printf("\n");
for(int i=0;i<Q;i++)
{
len=dis[query[i<<1].q]+dis[query[i<<1|1].q]-dis[ans[i]]*2;
printf("%d\n",len);
}
}
return 0;
}