天天看点

hdu2586 LCA

给一颗无向树有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;
}