G - How far away - 倍增LCA模板

  • G - How far away ?

  •  HDU - 2586 
  • 题意:
  • n个房子用n-1条路连接起来(也就是一棵树),对于每一个询问,
  • 求出2个房子直接的线路距离
  • 思路:
  • 这个题目只要建立一个树,然后查询任意2个点之间的距离,假设B和C的最近公共祖先是A,那么对于整个树的根节点D,
  • 都有:|BD|+|CD|-|AD|*2=|BC|事先求出所有点到1的距离d,
  • 分析:倍增求LCA
  • deep[x],表示x节点的深度。
  • ans[x][i] ,这个数组表示标号为x节点向上跳2^i步的节点。dfs时预处理ans[x][0]=所有节点向上跳一个就是他的父亲节点。
  • ans[x][1]=ans[ans[x][0]][0];例如2^4=2^3+2^3。x向上跳2的i次的节点=x向上跳i-1次方的这个节点向上跳i-1次方
  • 给定两个节点。要我们求他们的lca 我们是把深度高的向上调。调整跟深度低的一样。首先我们j从log2(n)开始跳,跳到0。我们要跳到他们lca的下面两个节点
  • #include<bits/stdc++.h>
    using namespace std;
    #define maxn 40006
    int deep[maxn],d[maxn],t;
    int ans[maxn][20],k,n;
    struct node
    {
        int v,w;
    };
    vector<node>mmp[maxn];
    void dfs(int u,int pre,int depth,int dis)
    {
        ans[u][0]=pre;
        d[u]=dis;
        deep[u]=depth;
        int len=mmp[u].size();
        for(int i=0; i<len; i++)
        {
            int v=mmp[u][i].v;
            if(v==pre)continue;
            dfs(v,u,depth+1,dis+mmp[u][i].w);
        }
    }
    void init()
    {
        for(int j=1; (1<<j)<n; j++)
        {
            k=j;
            for(int i=1; i<=n; i++)
            {
                ans[i][j]=-1;
                int temp=ans[i][j-1];
                if(temp==-1)
                    continue;
                ans[i][j]=ans[temp][j-1];
            }
        }
    }
    int lca(int u,int v)
    {
        if(deep[u]<deep[v])swap(u,v);
        for(int i=k; i>=0; i--)
            if(deep[u]-(1<<i)>=deep[v])
                u=ans[u][i];
        if(u==v)
            return u;
        for(int i=k; i>=0; i--)
            if(ans[u][i]!=ans[v][i])
            {
                u=ans[u][i];
                v=ans[v][i];
            }
        return ans[u][0];
    }
    int main()
    {
        ios::sync_with_stdio(false);
        cin>>t;
        while(t--)
        {
            int m,u,v,w;
            cin>>n>>m;
            for(int i=1; i<=n; i++)
                mmp[i].clear();
            for(int i=1; i<n; i++)
            {
                cin>>u>>v>>w;
                mmp[u].push_back((node)
                {
                    v,w
                });
                mmp[v].push_back((node)
                {
                    u,w
                });
            }
            dfs(1,-1,1,0);
            init();
            while(m--)
            {
                cin>>u>>v;
                int fa=lca(u,v);
                cout<<d[u]+d[v]-2*d[fa]<<endl;
            }
        }
        return 0;
    }
    

     

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值