LCA小结

来源:互联网 发布:红米note3数据经常断网 编辑:程序博客网 时间:2024/06/04 08:43

LCA小结 A Summary for LCA

Ⅰ. LCA

  • 什么是LCA
    Lowest Common Ancestor, 指的是树上两点的最近公共祖先。
    有了它, 我们可以高效地求解树上两点间的距离、最大权值边等信息。
  • LCA的时间复杂度
    • 暴力 O(n+m+qn)
    • 倍增法 O(n+m+nlogn+qlogn)
    • 欧拉序列与RMQ O(n+m+nlogn+q)
    • Tarjan离线算法 O(n+m+q)
    • 树链剖分 O(n+m+qlogn)

Ⅱ. LCA的代码模版

,RMQ,Tarjan线,
,lca()

  • 暴力
//brute forcevector<int> G[N];int fa[N], dep[N];void dfs(int u, int f, int d) {    fa[u] = f;    dep[u] = d;    for(int i = 0; i < G[u].size(); ++i) {        int v = G[u][i];        if(v == f) continue;        dfs(v, u, d + 1);    }}void init() {    dfs(root, -1, 0);}int lca(int u, int v) {    if(dep[u] > dep[v]) swap(u, v);    while(dep[v] > dep[u]) v = fa[v];    while(u != v) {        u = fa[u];        v = fa[v];    }    return u;}
  • 倍增法
//doublingvector<int> G[N];const int LOG = 18;int p[LOG][N], dep[N];void dfs(int u, int f, int d) {    dep[u] = d;    p[0][u] = f;    for(int i = 0; i < G[u].size(); ++i) {        int v = G[u][i];        if(v == f) continue;        dfs(v, u, d + 1);    }}void init() {    dfs(root, -1, 0);    for(int i = 0; i + 1 < LOG; ++i)        for(int v = 1; v <= n; ++v)            if(p[i][v] < 0) p[i + 1][v] = -1;            else p[i + 1][v] = p[i][p[i][v]];}int lca(int u, int v) {    if(dep[u] > dep[v]) swap(u, v);    for(int i = 0; i < LOG; ++i)        if(dep[v] - dep[u] >> i & 1)            v = p[i][v];    if(u == v) return u;    for(int i = LOG - 1; ~i; --i) {        if(p[i][u] != p[i][v]) {            u = p[i][u];            v = p[i][v];        }    }    return p[0][u];}
  • 欧拉序列与RMQ
//Euler Sequence & RMQ(ST)int getMin(int x, int y) {    return dep[x] < dep[y] ? x : y;}struct SparseTable {    int dp[20][N << 1];    void init(int n) {        for(int i = 1; i <= n; ++i) dp[0][i] = i;        for(int i = 1; (1 << i) <= n; ++i)            for(int j = 1; j + (1 << i) - 1 <= n; ++j)                dp[i][j] = getMin(dp[i - 1][j],                                  dp[i - 1][j + (1 << i - 1)]);    }    int RMQ(int l, int r) {        int k = 31 - __builtin_clz(r - l + 1);        return getMin(dp[k][l], dp[k][r - (1 << k) + 1]);    }} st;vector<int> G[N];int vs[N << 1], dep[N << 1], first[N], dfsNum;void dfs(int u, int f, int d) {    vs[++dfsNum] = u;    dep[dfsNum] = d;    first[u] = dfsNum;    for(int i = 0; i < G[u].size(); ++i) {        int v = G[u][i];        if(v == f) continue;        dfs(v, u, d + 1);        vs[++dfsNum] = u;        dep[dfsNum] = d;    }}void init() {    dfsNum = 0;    dfs(root, -1, 0);    st.init(2 * n - 1);}int lca(int u, int v) {    if(first[u] > first[v]) swap(u, v);    int idx = st.RMQ(first[u], first[v]);    return vs[idx];}
  • Tarjan离线算法
//Tarjan-lca & Disjoint Setstruct Query {    int v, id;};vector<Query> Q[N];int ans[MAXQ], ancestor[N], vis[N];int find(int x) {    return ancestor[x] = ancestor[x] == x ? x : find(ancestor[x]);}vector<int> G[N];void tarjan(int u) {    vis[u] = true;    ancestor[u] = u;    for(int i = 0; i < G[u].size(); ++i) {        int v = G[u][i];        if(vis[v]) continue;        tarjan(v);        ancestor[v] = u;    }    for(int i = 0; i < Q[u].size(); ++i) {        Query& q = Q[u][i];        if(vis[q.v]) ans[q.id] = find(q.v);    }}
  • 树链剖分
//HLD-lcaint lca(int u, int v) {    int ret;    while(true) {        if(top[u] == top[v]) {            ret = dep[u] < dep[v] ? u : v;            break;        } else if(dep[top[u]] > dep[top[v]])            u = fa[top[u]];        else v = fa[top[v]];    }    return ret;}

Ⅲ. LCA的题目特点

  • dp
  • lca
0 0
原创粉丝点击