zoukankan      html  css  js  c++  java
  • [hdu5266]区间LCA

    题意:给一棵树,求节点L,L+1,...R的最近公共祖先

    思路:先对树dfs一下,从根1出发,经过每条边时记录一下终点和到达这个点的时间截,令r[u]表示到达u这个节点的最早时间截,t[x]表示在时间截x时到达的节点编号,假设对于两个节点u,v,设r[u]<r[v],则在t[r[u]], t[r[u]+1], ..., t[r[v]]这个序列里面一定包含了u和v的LCA。要找出这个LCA也不难,由于这个序列里面的所有节点只有u和v的LCA这个节点的r值最小,于是可以用RMQ求出这个最小r值,然后再利用t数组就得到了LCA的节点编号。对于多个节点的LCA处理方法类似,只需找到多个节点中的r值的最小和最大值,相当于找到了r[u]和r[v],剩下的就与两个点的LCA一样了。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    #pragma comment(linker, "/STACK:10240000,10240000")
    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <cstdlib>  
    #include <vector>
    #include <algorithm>
    #include <queue>
    using namespace std;
     
    const int maxn = 3e5 + 7;
     
    struct Graph {
        vector<vector<int> > G;
        void clear() { G.clear(); }
        void resize(int n) { G.resize(n + 2); }
        vector<int> & operator [] (int x) { return G[x]; }
        int size() { return G.size(); }
        void add(int u, int v) { G[u].push_back(v); }
    };
    Graph G;
     
    struct ST {
        struct FI {
            int a[21];
            int & operator [] (int x) {
                return a[x];
            }
        };
        vector<FI> dp;
        vector<int> T;
     
        void init(int a[], int n, int (*F)(intint)) {
            dp.clear();
            dp.resize(n);
            for (int i = 0; i < n; i ++) dp[i][0] = a[i];
            for (int j = 1; (1 << j) <= n; j ++) {
                for (int i = 0; i + (1 << j) - 1 < n; i ++) {
                    dp[i][j] = F(dp[i][j - 1], dp[i + (1 << (j - 1))][j - 1]);
                }
            }
            T.clear();
            T.resize(n);
            T[1] = 0;
            for (int i = 2; i <= n; i ++) {
                T[i] = T[i - 1];
                if ((i & (i - 1)) == 0) T[i] ++;
            }
        }
        int query(int L, int R, int (*F)(intint)) {
            int t = T[R - L + 1];
            return F(dp[L][t], dp[R - (1 << t) + 1][t]);
        }
    };
    int fmin(int a, int b) { return a < b? a : b; }
    int fmax(int a, int b) { return a > b? a : b; }
    struct LCA {
        int clock, r[maxn], t[2 * maxn], b[2 * maxn];
        bool vis[maxn];
        ST st0, st1, st2;
        void dfs(int rt) {
            r[rt] = clock;
            t[clock ++] = rt;
            vis[rt] = true;
            int sz = G[rt].size();
            for (int i = 0; i < sz; i ++) {
                int u = G[rt][i];
                if (!vis[u]) {
                    dfs(u);
                    t[clock ++] = rt;
                }
            }
        }
        void work() {
            clock = 0;
            memset(vis, 0, sizeof(vis));
            dfs(1);
            for (int i = 0; i < clock; i ++) b[i] = r[t[i]];
            st0.init(b, clock, fmin);
            st1.init(r + 1, (clock + 1) >> 1, fmax);
            st2.init(r + 1, (clock + 1) >> 1, fmin);
        }
        int lca_all(int L, int R) {
            L --; R --;
            int lp = st2.query(L, R, fmin), rp = st1.query(L, R, fmax);
            return t[st0.query(lp, rp, fmin)];
        }
    };
     
    LCA lca;
    int main() {
    #ifndef ONLINE_JUDGE
        freopen("in.txt""r", stdin);
    #endif // ONLINE_JUDGE
        int n, m;
        while (cin >> n) {
            G.clear();
            G.resize(n);
            for (int i = 0; i < n - 1; i ++) {
                int u, v;
                scanf("%d%d", &u, &v);
                G.add(u, v);
                G.add(v, u);
            }
            lca.work();
            cin >> m;
            for (int i = 0; i < m; i ++) {
                int L, R;
                scanf("%d%d", &L, &R);
                printf("%d ", lca.lca_all(L, R));
            }
        }
        return 0;
    }
  • 相关阅读:
    浅谈HTTPS协议和SSL、TLS之间的区别与关系
    ECC加密算法原理入门介绍
    用实例给新手讲解RSA加密算法
    ECC椭圆曲线详解(有具体实例)
    设置VMware随系统开机自动启动并引导虚拟机操作系统
    Windows自带的端口转发工具netsh使用方法
    JAVA中使用P和Q分量计算N和D进行RSA运算
    VirtualBox虚拟机和主机之间的通信
    centos 系统管理维护指南
    页面找不到js方法的原因,关于EasyUI
  • 原文地址:https://www.cnblogs.com/jklongint/p/4572399.html
Copyright © 2011-2022 走看看