HDU-2586-How far away ?(倍增求LCA模板)

4 篇文章 0 订阅

题目链接:HDU-2586-How far away ?

倍增求LCA:
1.先转化成有根树。
2.dfs求出每个点的深度
3.初始化anc数组
4.倍增查询

#include<bits/stdc++.h>
using namespace std;
const int maxn=4e4+7;
int anc[maxn][20],deep[maxn],d[maxn],k;
int rt,n;
struct Edge
{
    int v,d;
    Edge(){}
    Edge(int _v,int _d):v(_v),d(_d){}
};
vector<Edge> adj[maxn];
void dfs(int u,int pre,int deep,int dis)
{
    anc[u][0]=pre;
    d[u]=dis;
    ::deep[u]=deep;
    for(int i=0;i<adj[u].size();i++)
    {
        int v=adj[u][i].v;
        if(v==pre) continue;
        dfs(v,u,deep+1,dis+adj[u][i].d);
    }
}
void init()
{
    for(int j=1;(1<<j)<n;j++)
    {
        k=j;
        for(int i=1;i<=n;i++)
        {
            anc[i][j]=-1;
            int p=anc[i][j-1];
            if(p==-1) continue;
            anc[i][j]=anc[p][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=anc[u][i];
    if(u==v) return u;
    for(int i=k;i>=0;i--)
        if(anc[u][i]!=anc[v][i])
        {
            u=anc[u][i];
            v=anc[v][i];
        }
    return anc[u][0];
}
int main()
{
    ios::sync_with_stdio(false);
    int T;
    cin>>T;
    while(T--)
    {
        int m,u,v,d;
        cin>>n>>m;
        for(int i=1;i<=n;i++) adj[i].clear();
        for(int i=1;i<n;i++)
        {
            cin>>u>>v>>d;
            adj[u].push_back(Edge(v,d));
            adj[v].push_back(Edge(u,d));
        }
        rt=1;
        dfs(rt,-1,1,0);
        init();
        while(m--)
        {
            cin>>u>>v;
            int fa=lca(u,v);
            cout << ::d[u]-::d[fa]+::d[v]-::d[fa] << endl;
        }
    }
    return 0;
}

dfs序+ST表:

#include<bits/stdc++.h>
using namespace std;
const int N=1e5+7;
struct Node
{
    int v,d;
};
vector<Node> adj[N];
int n;
namespace LCA
{
    int ord[N<<1],d[N<<1],fir[N],dp[N<<1][20],mm[N<<1],m=0;
    void dfs_lca(int u,int p,int deep)
    {
        ord[++m]=u;
        d[m]=deep;
        fir[u]=m;
        for(int i=0;i<adj[u].size();++i)
        {
            int v=adj[u][i].v;
            if(v==p) continue;
            dfs_lca(v,u,deep+1);
            ord[++m]=u;
            d[m]=deep;
        }
    }
    void init_RMQ()
    {
        mm[0] = -1;
        for(int i=1;i<=m;++i)
        {
            mm[i]= ((i&(i-1))==0)?mm[i-1]+1:mm[i-1];
            dp[i][0]=i;
        }
        for(int j=1;j<=mm[m];++j)
            for(int i=1;i+(1<<j)-1<=m;++i)
            {
                int x=dp[i][j-1],y=dp[i+(1<<(j-1))][j-1];
                dp[i][j]=d[x]<d[y]?x:y;
            }
    }
    int lca(int u,int v)
    {
        u=fir[u],v=fir[v];
        if(u>v) swap(u,v);
        int k=mm[v-u+1];
        int x=dp[u][k],y=dp[v-(1<<k)+1][k];
        return d[x]<d[y]?ord[x]:ord[y];
    }
    void init(int u)
    {
        m=0;
        dfs_lca(u,0,0);
        init_RMQ();
    }
}
int d[N];
void dfs(int u,int p)
{
    for(auto e : adj[u])
    {
        int v=e.v,c=e.d;
        if(v==p) continue;
        d[v]=d[u]+c;
        dfs(v,u);
    }
}
int main()
{
    int T;
    scanf("%d",&T);
    while(T--)
    {
        int q;
        scanf ("%d%d",&n,&q);
        for(int i=1;i<=n;++i) adj[i].clear();
        for(int i=1;i<n;++i)
        {
            int u,v,c;
            scanf("%d%d%d",&u,&v,&c);
            adj[u].push_back({v,c});
            adj[v].push_back({u,c});
        }
        d[1]=0;
        LCA::init(1);
        dfs(1,0);
        while(q--)
        {
            int u,v;
            scanf("%d%d",&u,&v);
            int lca=LCA::lca(u,v);
            printf("%d\n",d[u]+d[v]-2*d[lca]);
        }
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值