POJ 1330 Nearest Common Ancestors(LCA模板)

來源:互聯網
上載者:User

標籤:

給定一棵樹求任意兩個節點的公用祖先

tarjan離線求LCA思想是,先把所有的查詢儲存起來,然後dfs一遍樹的時候在判斷。如果當前節點是要求的兩個節點當中的一個,那麼再判斷另外一個是否已經訪問過,如果訪問過的話,那麼它的最近公用祖先就是當前節點祖先。

下面是tarjan離線模板:

#include <cstdio>#include <cstring>#include <algorithm>using namespace std;const int maxn = 10010;struct Edge {    int to, next;}edge[maxn * 2];//查詢 struct Query {    int q, next;    int index;}query[maxn * 2];int tot, head[maxn];//查詢的前向星 int cnt, h[maxn];//查詢的答案儲存在ans中 int ans[maxn * 2];int fa[maxn];//並查集 int r[maxn];//並查集集合個數 int ancestor[maxn];//祖先 bool vis[maxn];//訪問標記 int Q;//查詢總數 void init(int n){    tot = 0;    cnt = 0;    Q = 0;    memset(h, -1, sizeof(h));    memset(head, -1, sizeof(head));    memset(fa, -1, sizeof(fa));    memset(ancestor, 0, sizeof(ancestor));    memset(vis, false, sizeof(vis));    for (int i = 1; i <= n; i++) r[i] = 1;}void addedge(int u, int v){    edge[tot].to = v;    edge[tot].next = head[u];    head[u] = tot++;}void addquery(int u, int v, int index){    query[cnt].q = v;    query[cnt].index = index;    query[cnt].next = h[u];    h[u] = cnt++;}int find(int x){    if (fa[x] == -1) return x;    return fa[x] = find(fa[x]);}void Union(int x, int y){    int t1 = find(x);    int t2 = find(y);    if (t1 != t2)    {        if (t1 < t2)        {            fa[t1] = t2;            r[t2] += r[t1];        }        else        {            fa[t2] = t1;            r[t1] += r[t2];        }    }}void LCA(int u)//tarjan離線演算法 {    vis[u] = true;    ancestor[u] = u;    for (int i = head[u]; i != -1; i = edge[i].next)    {        int v = edge[i].to;        if (vis[v]) continue;        LCA(v);        Union(u, v);        ancestor[find(u)] = u;    }    for (int i = h[u]; i != -1; i = query[i].next)    {        int v = query[i].q;        if (vis[v])        {            ans[query[i].index] = ancestor[find(v)];        }    }}bool in[maxn];int main(){    int T, n;    scanf("%d", &T);    while (T--)    {        scanf("%d", &n);        init(n);        memset(in, false, sizeof(in));        int u, v;        for (int i = 1; i < n; i++)        {            scanf("%d %d", &u, &v);            in[v] = true;            addedge(u, v);            addedge(v, u);        }        scanf("%d %d", &u, &v);        addquery(u, v, Q);//添加查詢         addquery(v, u, Q++);        int root;        for (int i = 1; i <= n; i++)         {            if (!in[i])            {                root = i;                break;            }        }        LCA(root);        for (int i = 0; i < Q; i++)//按照順序列印出來答案             printf("%d\n", ans[i]);    }    return 0;}

RMQ&LCA線上模板:

RMQ st演算法是用來求一段連續的區間最值問題的,如果將樹看成一個線性結構,那麼它可以快速求出一段區間的最值,那麼就可以利用它求出LCA,首先求出一個樹的歐拉序列(就是dfs序),然後每個節點都有深度,都有到根節點的距離。儲存一個第一次訪問到某個節點的編號。這樣求兩個點的LCA就是求從歐拉序列當中的一段到另外一段(連續的)深度的最小值。直接RMQ就可以了。模板如下:

#include <cstdio>#include <iostream>#include <cstring>#include <cmath>#include <cstdlib>#include <algorithm>using namespace std;typedef long long ll;const int maxn = 20010;int tot, head[maxn];struct Edge {    int to, next;}edge[maxn];int occur[maxn];int first[maxn];int dep[maxn];bool vis[maxn];int m;void init(){    tot = 0;    memset(head, -1, sizeof(head));    memset(vis, false, sizeof(vis));    memset(first, 0, sizeof(first));    m = 0;}void addedge(int u, int v){    edge[tot].to = v;    edge[tot].next = head[u];    head[u] = tot++;}void dfs(int u, int depth){    occur[++m] = u;    dep[m] = depth;    if (!first[u])        first[u] = m;    for (int i = head[u]; i != -1; i = edge[i].next)    {        int v = edge[i].to;        dfs(v, depth + 1);        occur[++m] = u;        dep[m] = depth;    }}int Rmin[maxn * 2][32];void RMQ(int n){    for (int i = 1; i <= n; i++)        Rmin[i][0] = i;    int k = (int)log2(n);    for (int j = 1; j <= k; j++)    {        for (int i = 1; i + (1 << j) - 1 <= n; i++)            Rmin[i][j] = dep[Rmin[i][j - 1]] < dep[Rmin[i + (1 << (j - 1))][j - 1]] ? Rmin[i][j - 1] : Rmin[i + (1 << (j - 1))][j - 1];    }}int query(int a, int b){    int l = first[a], r = first[b];    if (l > r)        swap(l, r);    int k = (int)log2(r - l + 1);    int tmp = dep[Rmin[l][k]] < dep[Rmin[r - (1 << k) + 1][k]] ? Rmin[l][k] : Rmin[r - (1 << k) + 1][k];    return occur[tmp];}int main(){    int T, n;    scanf("%d", &T);    while (T--)    {        init();        scanf("%d", &n);        int a, b;        for (int i = 1; i < n; i++)        {            scanf("%d %d", &a, &b);            addedge(a, b);            vis[b] = true;        }        int root;        for (int i = 1; i <= n; i++)        {            if (!vis[i])            {                root = i;                break;            }        }        dfs(root, 1);        scanf("%d %d", &a, &b);        RMQ(m);        printf("%d\n", query(a, b));    }    return 0;}

 

POJ 1330 Nearest Common Ancestors(LCA模板)

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.