算法笔记--lca倍增算法

算法笔记

模板:

vector<int>g[N];
vector<int>edge[N];
int anc[20][N];
int deep[N];
int h[N];
void dfs(int o,int u,int w)
{
    if(u!=o)deep[u]=deep[o]+1,h[u]=h[o]+w;
    for(int j=0;j<g[u].size();j++)
    {
        if(g[u][j]!=o)
        {
            anc[0][g[u][j]]=u;
            for(int i=1;i<20;i++)anc[i][g[u][j]]=anc[i-1][anc[i-1][g[u][j]]];
            dfs(u,g[u][j],edge[u][j]);
        }
    }
}
int lca(int u,int v)
{
    if(deep[u]<deep[v])swap(u,v);
    for(int i=19;i>=0;i--)if(deep[anc[i][u]]>=deep[v])u=anc[i][u];
    if(u==v)return u;
    for(int i=19;i>=0;i--)if(anc[i][u]!=anc[i][v])u=anc[i][u],v=anc[i][v];
    return anc[0][u];
}
int dis(int u,int v)
{
    int l=lca(u,v);
    return h[u]+h[v]-2*h[l];
}

例题:

1.CODEVS 2370 小机房的树

带权lca

代码:

#include<bits/stdc++.h>
using namespace std;
#define ll long long
const int INF=0x3f3f3f3f;
const int N=5e4+5;
vector<int>g[N];
vector<int>edge[N];
int anc[20][N];
int deep[N];
int h[N];
void dfs(int o,int u,int w)
{
    if(u!=o)deep[u]=deep[o]+1,h[u]=h[o]+w;
    for(int j=0;j<g[u].size();j++)
    {
        if(g[u][j]!=o)
        {
            anc[0][g[u][j]]=u;
            for(int i=1;i<20;i++)anc[i][g[u][j]]=anc[i-1][anc[i-1][g[u][j]]];
            dfs(u,g[u][j],edge[u][j]);
        }
    }
}
int lca(int u,int v)
{
    if(deep[u]<deep[v])swap(u,v);
    for(int i=19;i>=0;i--)if(deep[anc[i][u]]>=deep[v])u=anc[i][u];
    if(u==v)return u;
    for(int i=19;i>=0;i--)if(anc[i][u]!=anc[i][v])u=anc[i][u],v=anc[i][v];
    return anc[0][u];
}
int dis(int u,int v)
{
    int l=lca(u,v);
    return h[u]+h[v]-2*h[l];
}
int main()
{
    ios::sync_with_stdio(false);
    cin.tie(0);
    int n,u,v,c,m;
    cin>>n;
    for(int i=0;i<n-1;i++)
    {
        cin>>u>>v>>c;
        g[u].push_back(v);
        g[v].push_back(u);
        edge[u].push_back(c);
        edge[v].push_back(c);
    }
    cin>>m;
    for(int i=0;i<20;i++)anc[i][0]=0;
    dfs(0,0,0);
    while(m--)
    {
        cin>>u>>v;
        cout<<dis(u,v)<<endl;
    }
    return 0;
}

2.CODEVS 1036 商务旅行

普通lca

代码:

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define ls rt<<1,l,m
#define rs rt<<1|1,m+1,r
const int INF=0x3f3f3f3f;
const int N=1e5+5;
vector<int>g[N];
int anc[20][N];
int deep[N];
void dfs(int o,int u)
{
    if(o!=u)deep[u]=deep[o]+1;
    for(int j=0;j<g[u].size();j++)
    {
        if(o!=g[u][j])
        {
            anc[0][g[u][j]]=u;
            for(int i=1;i<20;i++)anc[i][g[u][j]]=anc[i-1][anc[i-1][g[u][j]]];
            dfs(u,g[u][j]);
        }
    }
}
int lca(int u,int v)
{
    if(deep[u]<deep[v])swap(u,v);
    for(int i=19;i>=0;i--)if(deep[anc[i][u]]>=deep[v])u=anc[i][u];
    if(u==v)return u;
    for(int i=19;i>=0;i--)if(anc[i][u]!=anc[i][v])u=anc[i][u],v=anc[i][v];
    return anc[0][u];
}
int dis(int u,int v)
{
    return deep[u]+deep[v]-2*deep[lca(u,v)];
}
void init()
{
    for(int i=0;i<20;i++)anc[0][1]=1;
    dfs(0,1);
}
int main()
{
    ios::sync_with_stdio(false);
    cin.tie(0);
    int n,m;
    cin>>n;
    for(int i=1;i<n;i++)
    {
        int a,b;
        cin>>a>>b;
        g[a].push_back(b);
        g[b].push_back(a);
    }
    init();
    cin>>m;
    int a,b,ans=0;
    cin>>a;
    for(int i=1;i<m;i++)
    {
        cin>>b;
        ans+=dis(a,b);
        a=b;
    }
    cout<<ans<<endl;
    return 0;
}

3.METO CODE P223 拉力赛

带权lca,当lca(a,b)==a时,韵韵才能参加。

代码:

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define ls rt<<1,l,m
#define rs rt<<1|1,m+1,r
#define pb push_back
const int INF=0x3f3f3f3f;
const int N=1e4+5;
vector<int>g[N];
vector<ll>edge[N];
int anc[20][N];
int deep[N];
ll h[N];
bool vis[N]={false};
int s;
void dfs(int o,int u,ll w)
{
    if(o!=u)deep[u]=deep[o]+1,h[u]=h[o]+w;
    for(int j=0;j<g[u].size();j++)
    {
        if(g[u][j]!=o)
        {
            anc[0][g[u][j]]=u;
            for(int i=1;i<20;i++)anc[i][g[u][j]]=anc[i-1][anc[i-1][g[u][j]]];
            dfs(u,g[u][j],edge[u][j]);
        }
    }
}
int lca(int u,int v)
{
    if(deep[u]<deep[v])swap(u,v);
    for(int i=19;i>=0;i--)if(deep[anc[i][u]]>=deep[v])u=anc[i][u];
    if(u==v)return u;
    for(int i=19;i>=0;i--)if(anc[i][u]!=anc[i][v])u=anc[i][u],v=anc[i][v];
    return anc[0][u];
}
ll dis(int u,int v)
{
    return h[u]+h[v]-2*h[lca(u,v)];
}
void init()
{
    for(int i=0;i<20;i++)anc[i][1]=1;
    dfs(0,1,1);
}
int main()
{
    ios::sync_with_stdio(false);
    cin.tie(0);
    int n,m,a,b;
    ll t;
    cin>>n>>m;
    for(int i=1;i<n;i++)
    {
        cin>>a>>b>>t;
        g[a].pb(b);
        g[b].pb(a);
        edge[a].pb(t);
        edge[b].pb(t);
    }
    init();
    int cnt=0;
    ll ans=0;
    for(int i=0;i<m;i++)
    {
        int a,b;
        cin>>a>>b;
        if(lca(a,b)==a)
        {
            cnt++;
            ans+=h[b]-h[a];
        }
        }
    cout<<cnt<<endl;
    cout<<ans<<endl;
    return 0;
}

4.HDU 2586 How far way?

带权lca

代码:

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define pb push_back
const int INF=0x3f3f3f3f;
const int N=4e4+5;
vector<int>g[N];
vector<int>edge[N];
int deep[N];
int h[N];
int anc[20][N];
bool vis[N]={false};
int s=1;
void dfs(int o,int u,int w)
{
    deep[u]=deep[o]+1;
    h[u]=h[o]+w;
    for(int j=0;j<g[u].size();j++)
    {
        if(g[u][j]!=o)
        {
            anc[0][g[u][j]]=u;
            for(int i=1;i<20;i++)anc[i][g[u][j]]=anc[i-1][anc[i-1][g[u][j]]];
            dfs(u,g[u][j],edge[u][j]);
        }
    }
}
int lca(int u,int v)
{
    if(deep[u]<deep[v])swap(u,v);
    for(int i=19;i>=0;i--)if(deep[anc[i][u]]>=deep[v])u=anc[i][u];
    if(u==v)return u;
    for(int i=19;i>=0;i--)if(anc[i][u]!=anc[i][v])u=anc[i][u],v=anc[i][v];
    return anc[0][u];
}
ll dis(int u,int v)
{
    return h[u]+h[v]-2*h[lca(u,v)];
}
void init()
{
    for(int i=0;i<20;i++)anc[i][1]=1;
    dfs(0,1,1);
}
int main()
{
    ios::sync_with_stdio(false);
    cin.tie(0);
    int t;
    cin>>t;
    while(t--)
    {
        int n,m,a,b,k;
        cin>>n>>m;
        for(int i=1;i<n;i++)
        {
            cin>>a>>b>>k;
            g[a].pb(b);
            g[b].pb(a);
            edge[a].pb(k);
            edge[b].pb(k);
            vis[b]=true;
        }
        init();
        for(int i=0;i<m;i++)
        {
            cin>>a>>b;
            cout<<dis(a,b)<<endl;
        }
        //cout<<endl;
    }
    return 0;
}

5.ZOJ P3195 Design the city

带权lca,三点之间的最短路径公式h[a]+h[b]+h[c]-h[lca(a,b)]-h[lca(a,c)]-h[lca(b,c)]。

代码:

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define pb push_back
const int INF=0x3f3f3f3f;
const int N=5e4+5;
vector<int>g[N];
vector<int>edge[N];
int deep[N];
int h[N];
int anc[20][N];
void dfs(int o,int u,int w)
{
    if(u!=o)deep[u]=deep[o]+1,h[u]=h[o]+w;
    for(int j=0;j<g[u].size();j++)
    {
        if(g[u][j]!=o)
        {
            anc[0][g[u][j]]=u;
            for(int i=1;i<20;i++)anc[i][g[u][j]]=anc[i-1][anc[i-1][g[u][j]]];
            dfs(u,g[u][j],edge[u][j]);
        }
    }
}
int lca(int u,int v)
{
    if(deep[u]<deep[v])swap(u,v);
    for(int i=19;i>=0;i--)if(deep[anc[i][u]]>=deep[v])u=anc[i][u];
    if(u==v)return u;
    for(int i=19;i>=0;i--)if(anc[i][u]!=anc[i][v])u=anc[i][u],v=anc[i][v];
    return anc[0][u];
}
int dis(int u,int v)
{
    return h[u]+h[v]-2*h[lca(u,v)];
}
void init()
{
    for(int i=0;i<20;i++)anc[i][0]=0;
    dfs(0,0,0);
}
int main()
{
    int n,q,a,b,c;
    bool flag=true;
    while(~scanf("%d",&n)&&n)
    {
        if(flag) flag=false;
        else printf("\n");
        for(int i=0;i<n;i++)g[i].clear(),edge[i].clear();
        for(int i=1;i<n;i++)
        {
            scanf("%d%d%d",&a,&b,&c);
            g[a].pb(b);
            g[b].pb(a);
            edge[a].pb(c);
            edge[b].pb(c);
        }
        init();
        scanf("%d",&q);
        while(q--)
        {
            scanf("%d%d%d",&a,&b,&c);
            printf("%d\n",h[a]+h[b]+h[c]-h[lca(a,b)]-h[lca(a,c)]-h[lca(b,c)]);
        }
    }
    return 0;
}

时间: 2024-10-01 04:11:06

算法笔记--lca倍增算法的相关文章

HDU 4547 LCA倍增算法

CD操作 Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 65535/32768 K (Java/Others)Total Submission(s): 1111    Accepted Submission(s): 297 Problem Description 在Windows下我们可以通过cmd运行DOS的部分功能,其中CD是一条很有意思的命令,通过CD操作,我们可以改变当前目录. 这里我们简化一下问题,假设只有一个根目录,

LCA倍增算法

LCA 算法是一个技巧性很强的算法. 十分感谢月老提供的模板. 这里我实现LCA是通过倍增,其实就是二进制优化. 任何一个数都可以有2的阶数实现 例如16可以由1 2 4 8组合得到 5可以由1 2 4 组合得到 便于读者理解 我放一道例题吧 Problem F: 挑战迷宫 Description 小翔和小明正在挑战一个神奇的迷宫.迷宫由n个房间组成,每个房间的编号为1~n,其中1号房间是他们俩初始位置, 所有房间一共由n-1条路连接,使得房间两两之间能够相互达到(构成一棵树),每条路的长度为W

算法笔记_071:SPFA算法简单介绍(Java)

目录 1 问题描述 2 解决方案 2.1 具体编码   1 问题描述 何为spfa(Shortest Path Faster Algorithm)算法? spfa算法功能:给定一个加权连通图,选取一个顶点,称为起点,求取起点到其它所有顶点之间的最短距离,其显著特点是可以求含负权图的单源最短路径,且效率较高.(PS:引用自百度百科:spfa是求单源最短路径的一种算法,它还有一个重要的功能是判负环(在差分约束系统中会得以体现),在Bellman-ford算法的基础上加上一个队列优化,减少了冗余的松弛

最近公共祖先 LCA 倍增算法

倍增算法可以在线求树上两个点的LCA,时间复杂度为nlogn 预处理:通过dfs遍历,记录每个节点到根节点的距离dist[u],深度d[u] init()求出树上每个节点u的2^i祖先p[u][i] 求最近公共祖先,根据两个节点的的深度,如不同,向上调整深度大的节点,使得两个节点在同一层上,如果正好是祖先结束,否则,将连个节点同时上移,查询最近公共祖先. void dfs(int u){ for(int i=head[u];i!=-1;i=edge[i].next){ int to=edge[i

算法笔记_066:Kruskal算法详解(Java)

目录 1 问题描述 2 解决方案 2.1 构造最小生成树示例 2.2 伪码及时间效率分析 2.3 具体编码(最佳时间效率)   1 问题描述 何为Kruskal算法? 该算法功能:求取加权连通图的最小生成树.假设加权连通图有n个顶点,那么其最小生成树有且仅有n - 1条边. 该算法核心思想:从给定加权连通图中,选择当前未被选择的,不能形成回路且权值最小的边,加入到当前正在构造的最小生成树中. 2 解决方案 2.1 构造最小生成树示例 下面请看一个具体示例: 给定一个加权连通图,其包含5个顶点,分

图论——LCA倍增算法【转】

[转载]:http://www.cnblogs.com/OUSUO/p/3805715.html?utm_source=tuicool&utm_medium=referral 1. DFS预处理出所有节点的深度和父节点 inline void dfs(int u) { int i; for(i=head[u];i!=-1;i=next[i]) { if (!deep[to[i]]) { deep[to[i]] = deep[u]+1; p[to[i]][0] = u; //p[x][0]保存x的

Tarjan 算法求 LCA / Tarjan 算法求强连通分量

[时光蒸汽喵带你做专题]最近公共祖先 LCA (Lowest Common Ancestors)_哔哩哔哩 (゜-゜)つロ 干杯~-bilibili tarjan LCA - YouTube Tarjan算法_LCA - A_Bo的博客 - CSDN博客 Tarjan离线算法求最近公共祖先(LCA) - 初学者 - CSDN博客 最近公共祖先(LCA) - riteme.site Fuzhou University OnlineJudge P3379 [模板]最近公共祖先(LCA) - 洛谷 |

算法笔记_070:BellmanFord算法简单介绍(Java)

目录 1 问题描述 2 解决方案 2.1 具体编码   1 问题描述 何为BellmanFord算法? Floyd算法功能:给定一个加权连通图,选取一个顶点,称为起点,求取起点到其它所有顶点之间的最短距离,其显著特点是可以求取含负权图的单源最短路径. Floyd算法思想: 第一,初始化所有点.每一个点保存一个值,表示从原点到达这个点的距离,将原点的值设为0,其它的点的值设为无穷大(表示不可达). 第二,进行循环,循环下标为从1到n-1(n等于图中点的个数).在循环内部,遍历所有的边,进行松弛计算

算法笔记--最短路算法

1.单源最短路问题 ①Dijkstra算法: 普通版: #define mem(a,b) memset((a),(b),sizeof(a)) const int INF=0x3f3f3f3f; const int N=105; int g[N][N]; int d[N]; bool vis[N]; int n,m; void Dijkstra(int s) { mem(d,INF); mem(vis,false); d[s]=0; while(true) { int v=-1; for(int