zoukankan      html  css  js  c++  java
  • HDU 2586 How far away ?【LCA模板题】

    传送门:http://acm.hdu.edu.cn/showproblem.php?pid=2586

    题意:给你N个点,M次询问。1~N-1行输入点与点之间的权值,之后M行输入两个点(a,b)之间的最近距离;

    思路:设d[maxn]是当前点到根结点的距离,则答案就是 d[a]-d[lca(a,b)]+d[b]-d[lca(a,b)];

    接下来介绍LCA(Least Common Ancestors)

    即最近公共祖先,是指在有根树中,找出某两个结点u和v最近的公共祖先。

    常见解法一般有三种

    这里讲解一种在线算法—倍增

    所谓倍增,就是按2的倍数来增大,也就是跳 1,2,4,8,16,321,2,4,8,16,32 …… 不过在这我们不是按从小到大跳,而是从大向小跳,即按……32,16,8,4,2,132,16,8,4,2,1来跳,如果大的跳不过去,再把它调小。


    首先我们定义fa[u][j]表示结点u的第2^j祖先 

    那么要怎么求出全部的fa数组呢

    不难发现fa[u][0]就是u的父亲结点 

    这些父亲结点我们可以直接初始化

    对于其他结点则有 

    f[u][j]=f[ fa[u][j-1] ] [j-1] 

    什么意思呢 

    u的第2^(j-1)祖先的第2^(j-1)祖先(2^(j-1)+2^(j-1)) 就是u的第2^j祖先


    预处理各节点深度+初始化fa数组

    void dfs(int x, int fa)
    {
        h[x] = h[fa] + 1;
        f[x][0] = fa;
        for(int i = 1; (1 << i) <= h[x]; i++)
            f[x][i] = f[f[x][i - 1]][i - 1];
        for(int i = head[x]; i; i = edges[i].next)
        {
            if(edges[i].to != fa)
            {
                d[edges[i].to] = d[x] + edges[i].w;
                dfs(edges[i].to, x);
            }
        }
    }

    预处理之后怎么求解LCA(u,v)呢 

    我么先假定h[u]>h[v] 

    则两点深度差 d=h[u]-h[v]

    现在我们要做的是把u升到与v同样的深度 

    while(h[x] > h[y])
            x = f[x][lg[h[x] - h[y]] - 1];//因为预处理的log函数是log2(i)+1所以要-1

    对于任意一个d 

    我们都能将其分解为d=2^{p_1}+2^{p_2}+...+2^{p_i}

    所以直接log_2{d}可以得到向上走的指数p

    而log函数需要预处理

    for(int i = 1; i <= maxn; i++)//log2(i)+1
        {
            if((1 << lg[i - 1]) == i)
                lg[i] = lg[i - 1] + 1;
            else
                lg[i] = lg[i - 1];
        }

    到相同高度后就可以开始查询LCA了 

    for(int i = lg[h[x]] - 1; i >= 0; i--)
        {
            if(f[x][i] != f[y][i])
                x = f[x][i], y = f[y][i];
        }

    大体思路就是 

    从u和v最远的祖先开始 

    如果u的第2^i祖先等于 v的第2^i祖先,就不移动 

    否则u和v同时上移2^i个深度 

    最后u的父亲一定是u和v的LCA 

    #include<iostream>
    #include<string.h>
    #include<cstdio>
    using namespace std;
    const int maxn = 4e4 + 10;
    int n, m;
    int tot;
    struct node
    {
        int to;
        int next;
        int w;
    };
    node edges[maxn << 1];
    int head[maxn];
    int lg[maxn];
    int h[maxn];
    int d[maxn];//当前结点到根结点的深度
    int f[maxn][30];//f[i][j] 表示 i 节点的 2^j 级祖先
    void add_edges(int u, int v, int w)
    {
        edges[++tot].to = v;
        edges[tot].next = head[u];
        edges[tot].w = w;
        head[u] = tot;
    }
    void dfs(int x, int fa)
    {
        h[x] = h[fa] + 1;
        f[x][0] = fa;
        for(int i = 1; (1 << i) <= h[x]; i++)
            f[x][i] = f[f[x][i - 1]][i - 1];
        for(int i = head[x]; i; i = edges[i].next)
        {
            if(edges[i].to != fa)
            {
                d[edges[i].to] = d[x] + edges[i].w;
                dfs(edges[i].to, x);
            }
        }
    }
    int lca(int x, int y)
    {
        if(h[x] < h[y])
            swap(x, y);
        while(h[x] > h[y])
            x = f[x][lg[h[x] - h[y]] - 1];
        if(x == y)
            return x;
        for(int i = lg[h[x]] - 1; i >= 0; i--)
        {
            if(f[x][i] != f[y][i])
                x = f[x][i], y = f[y][i];
        }
        return f[x][0];
    }
    int main()
    {
        int T;
        scanf("%d", &T);
        for(int i = 1; i <= maxn; i++)//log2(i)+1
        {
            if((1 << lg[i - 1]) == i)
                lg[i] = lg[i - 1] + 1;
            else
                lg[i] = lg[i - 1];
        }
        while(T--)
        {
            tot = 0;
            memset(head, 0, sizeof(head));
            scanf("%d%d", &n, &m);
            int i, j, k;
            for(int t = 1; t < n; t++)
            {
                scanf("%d%d%d", &i, &j, &k);
                add_edges(i, j, k);
                add_edges(j, i, k);
            }
            dfs(1, -1);
            for(int t = 1; t <= m; t++)
            {
                scanf("%d%d", &i, &j);
                cout << d[i] + d[j] - 2 * d[lca(i, j)] << endl;
            }
        }
    }
  • 相关阅读:
    MongoDB_聚合
    MongoDB_基本操作
    MongoDB_"Error parsing YAML config file: yaml-cpp: error at line 3, column 9: illegal map value"解决方法
    MongoDB_安装
    beautifulsoup模块
    python发送邮件
    selenium常用操作
    selenium元素定位
    requests模块的高级用法
    继承
  • 原文地址:https://www.cnblogs.com/yyaoling/p/12260418.html
Copyright © 2011-2022 走看看