• 倍增求lca


    这是一个在线算法——这是非常重要的一点,求一次的复杂度是logn

    总复杂度为mlogn

    个人过的,介绍几题1036 商务旅行 codevs

    #include<cstdio>
    #include<algorithm>
    #include<iostream>
    #include<cmath>
    #include<cstring>
    #include<string>
    #include<vector>
    const int MAXN=30007;
    using namespace std;
    vector<int>to[MAXN];//记录到达的边
    int n,deep[30007],a[30007],m,f[MAXN][20];
    
    void init();
    void dfs(int x,int dfn,int fa);
    int lca(int x,int y);
    void init_f();
    
    int main()
    {
        int x,y;
        scanf("%d",&n);
        init();
        for (int i=1;i<n;i++)
        {
            scanf("%d%d",&x,&y);
            to[x].push_back(y);
            to[y].push_back(x);
        }
        dfs(1,1,-1);
        init_f();
        scanf("%d",&m);
        a[1]=0;
        for (int i=2;i<=m+1;i++)
            scanf("%d",&a[i]);
        int ans=0;
        for (int i=1;i<=m;i++)
        {
            x=lca(a[i],a[i+1]);
            ans+=(deep[a[i]]+deep[a[i+1]]-2*deep[x]);    
        }    
        cout<<ans-1<<endl;//应为点比经过的边多一
    }
    void init()
    {
        for (int i=1;i<=n;i++)
        {
            to[i].clear();
        }
        memset(deep,0,sizeof(deep));
        memset(a,0,sizeof(a));
        memset(f,-1,sizeof(f));
    }
    void dfs(int x,int dfn,int fa)//dfn记录的是深度,fa是父亲
    {
        deep[x]=dfn;
        f[x][0]=fa;
        int xx=to[x].size();
        for (int i=0;i<xx;i++)
        {
            if (to[x][i]!=fa) dfs(to[x][i],dfn+1,x);
        }
    }
    void init_f()//初始化f的值,以f[x][0]从dfs中求出来更新其他父亲。
    {
        for (int j=1;(1<<j)<=n;j++)
            for (int i=1;i<=n;i++)
                if (f[i][j-1]!=-1) f[i][j]=f[f[i][j-1]][j-1];
    }
    int lca(int x,int y)
    {
        int i;
        if (deep[x]<deep[y]) swap(x,y);//注意!这个必要的,否则下面影响
        for (i=0;(1<<i)<=deep[x];i++);
        i--;
        for (int j=i;j>=0;j--)
            if (deep[x]-(1<<j)>=deep[y]) x=f[x][j];//使其深度相同
        if (x==y) return x;
        for (int j=i;j>=0;j--)
        {
            if (f[x][j]!=-1&&f[x][j]!=f[y][j])
            {
                x=f[x][j];
                y=f[y][j];
            }
        }    
        return f[x][0];
    }

    另外一题难度差不多,只是边上多了一个权值,这时只是dfs稍加改进即可

    http://codevs.cn/problem/2370/

    也是codevs上的题,还可以。

    题意也是一眼题

    #include<cstdio>
    #include<algorithm>
    #include<iostream>
    #include<cmath>
    #include<cstring>
    #include<string>
    #include<vector>
    const int MAXN=50007;
    using namespace std;
    vector<int> to[MAXN],zhi[MAXN];
    int n,m,deep[MAXN],f[MAXN][20],dis[MAXN];
    
    void init();
    void init_f();
    int lca(int a,int b);
    void dfs(int x,int dfn,int fa,int where);
    
    int main()
    {
        int x,y,z;
        init();
        scanf("%d",&n);
        for (int i=1;i<n;i++)
        {
            scanf("%d%d%d",&x,&y,&z);
            to[x].push_back(y);
            to[y].push_back(x);
            zhi[x].push_back(z);
            zhi[y].push_back(z);
        }
        dfs(0,1,-1,-1);
        init_f();
        scanf("%d",&m);
        for (int i=1;i<=m;i++)
        {
            scanf("%d%d",&x,&y);
            z=lca(x,y);
            cout<<dis[x]+dis[y]-2*dis[z]<<endl;
        }
    }
    void init()
    {
        for (int i=1;i<=MAXN;i++)
        {
            to[i].clear();
            zhi[i].clear();
        }
        memset(f,0,sizeof(f));
        memset(deep,0,sizeof(deep));
    }
    void dfs(int x,int dfn,int fa,int where)
    {
        deep[x]=dfn;
        if (fa==-1) dis[x]=0;
        else dis[x]=dis[fa]+zhi[fa][where];
        int xx=to[x].size();
        for (int i=0;i<xx;i++)
        {
            if (to[x][i]==fa) continue;
            f[to[x][i]][0]=x;
            dfs(to[x][i],dfn+1,x,i);
        }
    }
    void init_f()
    {
        for (int j=1;(1<<j)<=n;j++)
            for (int i=0;i<n;i++)
                if (f[i][j-1]!=-1) f[i][j]=f[f[i][j-1]][j-1];    
    }
    int lca(int a,int b)
    {
        if (deep[a]<=deep[b]) swap(a,b);
        int i;
        for (i=0;(1<<i)<=deep[a];i++);
        i--;
        for (int j=i;j>=0;j--)
            if (deep[a]-(1<<j)>=deep[b]) a=f[a][j];
        if (a==b) return a;
        for (int j=i;j>=0;j--)
        {
            if (f[a][j]!=-1&&f[a][j]!=f[b][j])
            {
                a=f[a][j];
                b=f[b][j];
            }
        }    
        return f[a][0];
    }

    代码不长,倍增实现,在线算法,复杂度O(mlogn)

  • 相关阅读:
    在 《超过 光速 的 方法》 里 的 回复
    超过 光速 的 方法
    在 《我对 相对论 提出了一个 修正,名为 “K氏修正”》 里 的 回复
    我对 相对论 提出了一个 修正,名为 “K氏修正”
    input 只读不能修改
    获取父iframe的高宽
    indexOf ie下的兼容问题
    英文单词自动换行
    textarea 限制字数
    js判断输入框的范围,并且只能输入数字
  • 原文地址:https://www.cnblogs.com/fengzhiyuan/p/6776103.html
Copyright © 2020-2023  润新知