您的位置:首页 > 其它

Codevs2370 小机房的树

2015-08-10 14:56 357 查看
题目大意:给定一棵无根树,树边带权,求树上两点的最近距离。

思路:典型的LCA问题,采用倍增的方法。这里介绍一下倍增法求LCA。记数组fa[i,j]表示节点i向上走2j2^j步所能达到的点,在给出直接的父子u,v时记录下fa[u,0]=v,此后利用fa[i][j]=fa[fa[i][j-1]][j-1]就能得到其它的值。利用dfs获得各个节点的深度dep[ ]。节点u,v在寻找LCA时,令dep[u]>dep[v],再让u向上直至dep[u]=dep[v],最后二者一起向上找,直至fa[u,0]=fa[v,0],此时停止寻找,则LCA=fa[u,0]。寻找时,令j从大到小枚举,发现fa[u,j]!=fa[v,j]就往上蹦2j2^j步。若要记录花费,只需使用数组g[i,j]表示从节点i向上蹦2j2^j步的费用,很容易得到g[i,0]=c以及g[i][j]=g[fa[i][j-1]][j-1]+g[i][j-1]。

注意:这是一个无向图,需要自己选定树根,这里我选的是0,并且需要双向存边,并在DFS中确定树的父子节点关系。

代码如下:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<vector>
using namespace std;
struct node
{
    int id,len;
    node(int id=0,int len=0):id(id),len(len){}
};
const int maxn=50005;
int n,m,costi[maxn],fa[maxn][25],g[maxn][20],dep[maxn];
int ans;
bool vis[maxn];
vector<node> son[maxn];

void build(int root,int depth)
{
    dep[root]=depth;
    vis[root]=1;
    vector<node>::iterator it;
    for (it=son[root].begin();it!=son[root].end();++it)
    {
        if (!vis[(*it).id])
        {
            fa[(*it).id][0]=root;
            g[(*it).id][0]=(*it).len;
            build((*it).id,depth+1);
        }
    }
}

int adjust(int u,int step)
{
    for (int j=20;j>=0;--j)
    {
        if ((1<<j)<=step)
        {
            ans+=g[u][j];
            u=fa[u][j];
            step-=(1<<j);
            if (step==0)
              return u;
        }
    }
}

void query(int u,int v)
{
    ans=0;
    if (u==v)
    {
        printf("0");
        return;
    }
    if (dep[u]<dep[v])
      swap(u,v);
    if (dep[u]!=dep[v])
      u=adjust(u,dep[u]-dep[v]);
    for (int j=20;j>=0;--j)
      if (fa[u][j]!=fa[v][j])
      {
           ans+=g[u][j];
           ans+=g[v][j];
           u=fa[u][j];
           v=fa[v][j];
      }
    if (u!=v)
    {
         ans+=g[u][0];
         ans+=g[v][0];
    }
    printf("%d\n",ans);
}

void init()
{
    scanf("%d",&n);
    int u,v,c;
    memset(fa,0,sizeof(fa));
    memset(vis,0,sizeof(vis));
    for (int i=1;i<=n-1;++i)
    {
        scanf("%d%d%d",&u,&v,&c);
        son[u].push_back(node(v,c));        
        son[v].push_back(node(u,c));
    }
    build(0,0);
    for (int j = 1; j < 20; ++j) 
      for (int i = 1; i <= n; ++i)
      {
          fa[i][j]=fa[fa[i][j-1]][j-1];
          g[i][j]=g[fa[i][j-1]][j-1]+g[i][j-1];
      }
    scanf("%d",&m);
    while (m--)
    {
        scanf("%d%d",&u,&v);
        query(u,v);
    }
}

int main()
{
    init();
    return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: