• 欧拉路径+ST表(模板)


    http://poj.org/problem?id=1330

    题意:给出一颗树,给出父子关系,求两点的lca。

    解法:dfs序+ST表:

    原理:

    欧拉序前序遍历得到的序列,叫dfs序,但数字可以重复出现,一进一出,叫欧拉序),会发现根结点总在中间,而根结点是该段序列深度最小的点

    因此两个点的LCA,就是在该序列上两个点第一次出现的区间内深度最小的那个点

    即在欧拉序中进行ST表在区间中找到最小深度的欧拉序。

    https://www.cnblogs.com/stxy-ferryman/p/7741970.html

     该欧拉序为:ABDBEGEBACFHFCA.

    如果要求D、G的lca通过ST表查询D、G间深度最小的欧拉序为B,即为D、G的lca。

    从D到G的欧拉路径一定会经过D、G的最近公共祖先,深度最小的结点即为最近公共祖先,转为欧拉序,就是求解区间最小值问题,ST表解决。

    见代码:

    #include <bits/stdc++.h>
    using namespace std;
    const int N = 40010, M = 80010;
    int pos[N];//记录每个结点的起始欧拉序下标
    int oula[M], ti , dep[M];//欧拉序以及欧拉序中的下标对应结点的深度
    int dp[M][29];//记录欧拉序区间的深度最小的结点
    int e[M] , ne[M] , h[N] , idx ;
    int n , q ;
    void add(int a , int b){
        e[idx] = b , ne[idx] = h[a] , h[a] = idx++;
    }
    
    void dfs(int u, int pre , int d)
    {
        oula[++ti] = u;
        dep[ti] = d ;
        pos[u] = ti;
        for (int i = h[u]; ~i; i = ne[i])
        {
            int j = e[i];
            if (j == pre)
                continue;
            dfs(j, u , d+1);
            oula[++ti] = u;
            dep[ti] = d ;
        }
    }
    
    int Min(int x , int y){//返回结点深度小的下标
        return dep[x] < dep[y] ? x : y;
    }
    
    void ST()
    {
        for (int i = 1; i <= ti; i++)
        {
            dp[i][0] = i ;
        }
        for(int j = 1 ; (1 << j) <= ti ; j++){//枚举区间
            for(int i = 1 ; i + (1 << j) - 1 <= ti ; i++){
                dp[i][j] = Min(dp[i][j-1] , dp[i+(1<<j-1)][j-1]) ;
            }
        }
    }
    int query(int a , int b){//获取a到b路径上的最小深度的欧拉序下标
        a = pos[a] ;//映射到欧拉序中去
        b = pos[b] ;
        if(a > b) swap(a , b);
        int l = log2(b - a + 1);
        return Min(dp[a][l] , dp[b-(1<<l)+1][l]);
    }
    
    int main(){
        #ifdef ONLINE_JUDGE
        #else
            freopen("D:\c++\in.txt", "r", stdin);
            //freopen("D:\c++\out.txt", "w", stdout);
        #endif
        memset(h , -1 , sizeof(h));
        int rt ;
        cin >> n ;
        for(int i = 1 ; i <= n ; i++){
            int a , b ;
            cin >> a >> b ;
            if(b == -1){
                rt = a ;
                continue;
            }
            add(a , b);
            add(b , a);
        }
        dfs(rt , 0 , 1);
        ST();
        cin >> q ;
        while(q--){
            int a , b ;
            cin >> a >> b ;
            cout << oula[query(a , b)] << endl;//返回的是下标转为结点
        }
    
    }
  • 相关阅读:
    OpenCV---直方图反向投影
    OpenCV---直方图的应用(均衡化和图像比较)
    ASP.NET WEB SERVICE 创建、部署与使用
    DataSet和DataTable有用的方法
    黑客网站
    局域网中工作组和域之间的差别
    索引使用原则(精)
    C# Web Service 初级教学
    Extjs下拉多选框
    如何在UltraEdit中高亮显示PB代码
  • 原文地址:https://www.cnblogs.com/nonames/p/12336393.html
Copyright © 2020-2023  润新知