How far away ? HDU

来源:互联网 发布:马家军调查知乎 编辑:程序博客网 时间:2024/05/01 15:17

题意:给你n个村庄,n-1条路将所有村庄联通,每条路都有自己的长度。m次提问,问a,b村庄之间路的长度。

分析:这个就是在一棵树上求两个点的距离嘛。LCA。因为数据范围比较小,暴力的话,每组时间复杂度为m*q,可以卡过去。

用Tarjan的话,每组时间复杂度为m+q,用Tarjan求LCA是一种离线做法,先把所有询问都存起来,然后相同起点的可以一起算。

d[i]:从根到i点的距离
f[i]:i的祖先
vis[i]:标记数组
edge[i]:存边
q[i]:存询问
col[i]:标记目前哪些点可以直接查找

主要的是并查集的使用~妙呀~
(PE是什么鬼,OUTPUT中说每组样例结束后空一行嘛,空了PE。。。不空A了。。

#include <iostream>#include <cstdio>#include <algorithm>#include <cmath>#include <cstring>#include <vector>#include <set>#include <map>using namespace std;#define ll long long#define mem(a,b) memset(a,b,sizeof(a))const int maxn = 4e4+10;struct node{    int to,pre,id,v;}edge[maxn*2];node q[maxn];int f[maxn],head[maxn],hq[maxn],vis[maxn],col[maxn];ll ans[maxn],d[maxn];void init(int n){    mem(edge,0);mem(vis,0);mem(head,-1);mem(hq,-1);mem(q,0);mem(col,0);mem(d,0);    for(int i=1;i<=n;i++)        f[i]=i;}int h=0;void addedge(int from,int to,int v,int id){    edge[h].to=to;edge[h].v=v;edge[h].id=id;edge[h].pre=head[from];    head[from]=h;}void addq(int from,int to,int v,int id){    q[h].to=to;q[h].v=v;q[h].id=id;q[h].pre=hq[from];    hq[from]=h;}void dfs(int u,int val){    d[u]=val;    for(int i=head[u];i>-1;i=edge[i].pre)    {        int v=edge[i].to;        if(!vis[v])        {            vis[v]=1;            dfs(v,val+edge[i].v);        }    }}int getf(int k){    if(k==f[k]) return k;    else return f[k]=getf(f[k]);}void uin(int a,int b){    int x=getf(a),y=getf(b);    if(x!=y) f[y]=x;}void Tarjan(int u){    for(int i=head[u];i>-1;i=edge[i].pre)    {        node e=edge[i];        if(!vis[e.to])        {            vis[e.to]=1;            Tarjan(e.to);            uin(u,e.to);        }    }    col[u]=1;    for(int i=hq[u];i>-1;i=q[i].pre)    {        node e=q[i];        if(!col[e.to]) continue;        ans[e.id]=d[u]+d[e.to]-2*d[f[getf(e.to)]];//不能直接f[e.to],因为这里确保是最上面的祖先,因为uin的时候f[y]=x,但是以y为爸爸的孩子们的爸爸还没有改到x~    }}int main(){    int T;    scanf("%d",&T);    while(T--)    {        int n,m;        h=0;        scanf("%d %d",&n,&m);        init(n);        for(int i=0;i<n-1;i++)        {            int a,b,k;            scanf("%d %d %d",&a,&b,&k);            addedge(a,b,k,i);h++;addedge(b,a,k,i);h++;        }        vis[1]=1;        dfs(1,0);h=0;        for(int i=1;i<=m;i++)        {            int a,b;            scanf("%d %d",&a,&b);            addq(a,b,0,i);h++;addq(b,a,0,i);h++;        }        memset(vis,0,sizeof(vis));vis[1]=1;        Tarjan(1);        for(int i=1;i<=m;i++)        {            printf("%I64d\n",ans[i]);        }      //  printf("\n");    }    return 0;}
原创粉丝点击