hdu2586 LCA应用 求树的任意两节点的距离

来源:互联网 发布:如何使用炒股软件 编辑:程序博客网 时间:2024/06/05 17:26

http://acm.hdu.edu.cn/showproblem.php?pid=2586

题意:给出一棵树,求两节点的的距离

解题思路:

直接BFS超时,所以要使用LCA(离线tarjan算法)。

例如求x,y节点的距离,那么先求出x,y的lca是u节点,那么结果就是dis[x]+dis[y]-2*dis[u]

#include<stdio.h>#include<string.h>#include<stdlib.h>#include<math.h>#include<iostream>#include<algorithm>#include<queue>#include<stack>#include<vector>#include<map>#include<set>#include<bitset>#define ll __int64using namespace std;#define N 40005vector<int>tree[N];//图的邻接表vector<pair<int,int> >Q[N];//询问int ans[N];//保存每个询问的结果int f[N];int dis[N];//dis[i]是root到i节点的距离int find(int x)//找父根节点{if(f[x]!=x){f[x]=find(f[x]);}return f[x];}void mark(int a,int b){    f[find(b)] = find(a);}void LCA(int u){    f[u]=u;for(int i=0; i<tree[u].size(); i++) //未visit子节点    {        LCA(tree[u][i]);        mark(u, tree[u][i]);//将子节点并到父结点的集合中    }for(int i=0; i<Q[u].size(); i++)//求当前节点与有关的节点的最近公共祖先{if(f[Q[u][i].first]!=-1)//如果另一个节点也已处理过{    ans[Q[u][i].second]=find(Q[u][i].first);}}}void callLCA(int root){    LCA(root);}vector<pair<int,int> >V[N];//记录无向图void init(int n){    memset(f,-1,sizeof(f));    memset(ans,-1,sizeof(ans));    for(int i=0;i<=n;i++)    {        tree[i].clear();        Q[i].clear();        V[i].clear();    }}int flag[N];int BFS_getPoint()//对无向图进行BFS,从而获取树的一个端点{    int start=1;    memset(flag,0,sizeof(flag));    queue<int>QUE;    QUE.push(start);    int lastOne=-1;    while(!QUE.empty())    {        int now=QUE.front();        QUE.pop();        lastOne=now;        flag[now]=1;        for(int i=0;i<V[now].size();i++)        {            if(flag[V[now][i].first]==0)            {                QUE.push(V[now][i].first);            }        }    }    return lastOne;}void BFS_calDis(int root)//记录root节点到所有节点的距离,并且初始化树{    memset(dis,0,sizeof(dis));    memset(flag,0,sizeof(flag));    queue<pair<int,int> >QUE;    pair<int,int>p,q;    p=make_pair(root,0);    QUE.push(p);    while(!QUE.empty())    {        q=QUE.front();        QUE.pop();        dis[q.first]=q.second;        flag[q.first]=1;        for(int i=0;i<V[q.first].size();i++)        {            if(flag[V[q.first][i].first]==0)            {                p=make_pair(V[q.first][i].first,q.second+V[q.first][i].second);                QUE.push(p);                tree[q.first].push_back(p.first);            }        }    }}int main(){int i,j,k;int t,n,m;scanf("%d",&t);while(t--){    int q;    scanf("%d%d",&n,&q);    init(n);    for(i=1;i<=n-1;i++)//记录无向图    {        int from,to,len;        scanf("%d%d%d",&from,&to,&len);        pair<int,int>p;        p=make_pair(to,len);        V[from].push_back(p);        p=make_pair(from,len);        V[to].push_back(p);    }    int get=BFS_getPoint();//找无向图形成的树的根节点    BFS_calDis(get);//形成树的有向图(父结点->子节点)    pair<int,int>p;    vector<pair<int,int> >Record;    Record.clear();    for(i=1;i<=q;i++)    {        int from,to;        scanf("%d%d",&from,&to);        p=make_pair(from,to);        Record.push_back(p);        p=make_pair(to,i);            Q[from].push_back(p);            p=make_pair(from,i);            Q[to].push_back(p);    }    callLCA(get);        for(i=1;i<=q;i++)        {            if(ans[i]==-1)            {printf("not connect");}            else            {                int len=dis[Record[i-1].first]+dis[Record[i-1].second]-2*dis[ans[i]];                printf("%d\n",len);            }        }}}/*input:13 21 2 103 1 151 22 3output:1025*/

0 0
原创粉丝点击