HDU 2586 /// tarjan离线求树上两点的LCA

题目大意:

询问一棵树里 u 到 v 的距离

可由 dis[ u到根 ] + dis[ v到根 ] - 2*dis[ lca(u,v) ] 得到

https://blog.csdn.net/csyzcyj/article/details/10051173

#include <bits/stdc++.h>
#define mem(i,j) memset(i,j,sizeof(i))
using namespace std;

const int N=40005, Q=205;
struct EDGE { int to, w, nt; }e[N<<1], q[Q<<1];
int head[N], tot, que[N], pos;  
// 题目数据可能有些问题 实际不止200个询问 WA了好多发 :(

int fa[N], dis[N], lca[Q];
bool vis[N];

int n, m, U[Q], V[Q];

void init() {
    tot=1; mem(head,0);
    pos=1; mem(que,0);
    mem(vis,0); mem(dis,0); 
}
void addE(int u,int v,int w) {
    e[tot].to=v, e[tot].w=w;
    e[tot].nt=head[u];
    head[u]=tot++;
}
void addQ(int u,int v,int w) {
    q[pos].to=v, q[pos].w=w;
    q[pos].nt=que[u];
    que[u]=pos++;
}

int getfa(int u) {
    if(fa[u]==u) return u;
    return fa[u]=getfa(fa[u]);
}

void Tarjan(int u) {
    fa[u]=u; vis[u]=1;
    for(int i=head[u];i;i=e[i].nt) {
        int v=e[i].to;
        if(!vis[v]) {
            dis[v]=dis[u]+e[i].w;
            Tarjan(v); fa[v]=u;
        }
    }
    for(int i=que[u];i;i=q[i].nt) {
        int v=q[i].to;
        if(vis[v]) lca[q[i].w]=getfa(v);
    }
}

int main()
{ 
    int t; scanf("%d",&t);
    while(t--) {
        scanf("%d%d",&n,&m);
        init();

        for(int i=1;i<n;i++) {
            int u,v,w; scanf("%d%d%d",&u,&v,&w);
            addE(u,v,w); addE(v,u,w);
        }
        for(int i=1;i<=m;i++) {
            scanf("%d%d",&U[i],&V[i]);
            addQ(U[i],V[i],i), addQ(V[i],U[i],i);
        }

        Tarjan(1);
        for(int i=1;i<=m;i++)
            printf("%d\n",dis[U[i]]+dis[V[i]]-2*dis[lca[i]]);

    }

    return 0;
}

 

posted @ 2018-11-25 22:30  _Jessie  阅读(176)  评论(0编辑  收藏  举报