zoukankan      html  css  js  c++  java
  • POJ 1330 Nearest Common Ancestors LCA

    题目链接:

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

    题意:

    给你一颗有根树,最后输入一对数(a,b),叫你求a和b的公共祖先。

    裸的lca,数据也很小,拿来练手不错。

    题解:

    1、tarjan_lca,离线,线性时间复杂度

    代码:

     1 #include<iostream>
     2 #include<cstdio>
     3 #include<cstring>
     4 #include<vector>
     5 using namespace std;
     6 
     7 const int maxn = 1e4 + 10;
     8 
     9 int n,root;
    10 int deg[maxn],vis[maxn],p[maxn];
    11 vector<int> tree[maxn],que[maxn];
    12 
    13 void init() {
    14     memset(deg, 0, sizeof(deg));
    15     for (int i = 0; i <= n; i++) tree[i].clear();
    16     for (int i = 0; i <= n; i++) que[i].clear();
    17     memset(vis, 0, sizeof(vis));
    18     root = -1;
    19 }
    20 //并查集:
    21 int fin(int x) { return p[x] = p[x] == x ? x : fin(p[x]); }
    22 void uni(int a, int b) {
    23     int pa = fin(a);
    24     int pb = fin(b);
    25     //不能写成p[pa]=pb,和tarjan算法有关;
    26     p[pb] = pa;
    27 }
    28 
    29 bool tarjan_LCA(int rt,int& ans) {
    30     p[rt] = rt;
    31     for (int i = 0; i < tree[rt].size(); i++) {
    32         int v = tree[rt][i];
    33         if (tarjan_LCA(v, ans)) return true;
    34         //把v并到rt上
    35         uni(rt, v);
    36     }
    37     //涂黑这一点
    38     vis[rt] = 1;
    39     //处理与rt有关的查询
    40     for (int i = 0; i < que[rt].size(); i++) {
    41         int qv = que[rt][i];
    42         if (vis[qv]) {
    43             ans = fin(qv);
    44             return true;
    45         }
    46     }
    47     return false;
    48 }
    49 
    50 int main() {
    51     int tc;
    52     scanf("%d", &tc);
    53     while (tc--) {
    54         scanf("%d", &n);
    55         init();
    56         for (int i = 0; i < n - 1; i++) {
    57             int u, v;
    58             scanf("%d%d", &u, &v);
    59             tree[u].push_back(v);
    60             deg[v]++;
    61         }
    62         int qu, qv;
    63         scanf("%d%d", &qu, &qv);
    64         que[qu].push_back(qv);
    65         que[qv].push_back(qu);
    66         for (int i = 1; i <= n; i++) if (deg[i] == 0) {
    67             root = i;
    68         }
    69         int ans;
    70         tarjan_LCA(root,ans);
    71         printf("%d
    ", ans);
    72     }
    73     return 0;
    74 }
    View Code

    2、在线LCA

     1 /*
     2 author: fenice
     3 algorithm: 在线LCA
     4 time: 预处理O(nlogn),查询O(logn)
     5 */
     6 
     7 #include<iostream>
     8 #include<cstdio>
     9 #include<cstring>
    10 #include<vector>
    11 #include<algorithm>
    12 using namespace std;
    13 
    14 const int maxn = 1e4 + 10;
    15 
    16 int n, root;
    17 int par[maxn];
    18 int anc[maxn][33];
    19 vector<int> tree[maxn];
    20 
    21 int hig[maxn];//求深度(根节点为0)
    22 void dfs(int cur, int h) {
    23     hig[cur] = h;
    24     for (int i = 0; i < tree[cur].size(); i++) {
    25         dfs(tree[cur][i], h + 1);
    26     }
    27 }
    28 
    29 //预处理:anc[i][j]表示i节点的第2^j个祖先,它的父亲是它的第2^0个祖先,以此从下往上推。
    30 void pre() {
    31     for (int i = 0; i < n; i++) anc[i][0] = par[i];
    32     for (int j = 1; j < 32; j++) {
    33         for (int i = 0; i < n; i++) {
    34             int x = anc[i][j - 1];
    35             if (x != -1) {
    36                 anc[i][j] = anc[x][j - 1];
    37             }
    38         }
    39     }
    40 }
    41 
    42 //在线LCA:
    43 int solve(int p, int q) {
    44     if (hig[p] < hig[q]) swap(p, q);
    45     int log;
    46     for (log = 0; (1 << log) <= hig[p]; log++); log--;
    47 
    48     //把p提到与q同一层,这里是二进制表示的一个应用。
    49     //例子:如果x比y大,那么x减去若干个(1<<i)一定可以变成y
    50     for (int i = log; i >= 0; i--) {
    51         if (anc[p][i] != -1 && hig[anc[p][i]] >= hig[q]) p = anc[p][i];
    52     }
    53 
    54     //这里比较容易漏
    55     if (p == q) return p;
    56 
    57     //p,q一起往上提
    58     for (int i = log; i >= 0; i--) {
    59         if (anc[p][i] != anc[q][i]) {
    60             p = anc[p][i];
    61             q = anc[q][i];
    62         }
    63     }
    64     return par[p];
    65 }
    66 
    67 void init() {
    68     memset(par, -1, sizeof(par));
    69     for (int i = 0; i <= n; i++) tree[i].clear();
    70     memset(anc, -1, sizeof(anc));
    71     root = -1;
    72 }
    73 
    74 int main() {
    75     int tc;
    76     scanf("%d", &tc);
    77     while (tc--) {
    78         scanf("%d", &n);
    79         init();
    80         for (int i = 0; i < n - 1; i++) {
    81             int u, v;
    82             scanf("%d%d", &u, &v); u--; v--;
    83             tree[u].push_back(v);
    84             par[v] = u;
    85         }
    86         //找根
    87         for (int i = 0; i < n; i++) if (par[i] == -1) {
    88             root = i; break;
    89         }
    90 
    91         dfs(root, 0);
    92         pre();
    93 
    94         int qu, qv;
    95         scanf("%d%d", &qu, &qv); qu--, qv--;
    96         printf("%d
    ", solve(qu, qv) + 1);
    97     }
    98     return 0;
    99 }
    View Code

    3、树链剖分

    #include<map>
    #include<set>
    #include<cmath>
    #include<queue>
    #include<stack>
    #include<ctime>
    #include<vector>
    #include<cstdio>
    #include<string>
    #include<bitset>
    #include<cstdlib>
    #include<cstring>
    #include<iostream>
    #include<algorithm>
    #include<functional>
    using namespace std;
    #define X first
    #define Y second
    #define mkp make_pair
    #define lson (o<<1)
    #define rson ((o<<1)|1)
    #define mid (l+(r-l)/2)
    #define sz() size()
    #define pb(v) push_back(v)
    #define all(o) (o).begin(),(o).end()
    #define clr(a,v) memset(a,v,sizeof(a))
    #define bug(a) cout<<#a<<" = "<<a<<endl
    #define rep(i,a,b) for(int i=a;i<(b);i++)
    #define scf scanf
    #define prf printf
    
    typedef long long LL;
    typedef vector<int> VI;
    typedef pair<int,int> PII;
    typedef vector<pair<int,int> > VPII;
    
    const int INF=0x3f3f3f3f;
    const LL INFL=0x3f3f3f3f3f3f3f3fLL;
    const double eps=1e-8;
    const double PI = acos(-1.0);
    
    const int maxn = 22222;
    
    vector<int> G[maxn];
    
    ///val:边权转点权,fat:父亲,dep:深度,siz:子树节点个数
    int fat[maxn], dep[maxn], siz[maxn];
    ///son:重儿子,top:链顶,id:dfs序
    int son[maxn], top[maxn], id[maxn];
    int n;
    
    ///求dep,siz;
    void dfs(int u, int d) {
        dep[u] = d;
        siz[u] = 1;
        int ma = -INF;
        son[u]=0;
        for (int i = 0; i < G[u].size(); i++) {
            int v = G[u][i];
            dfs(v, d + 1);
            siz[u] += siz[v];
            if (ma < siz[v]) {
                son[u] = v;
                ma = siz[v];
            }
        }
    }
    ///求top,id
    int _tot;
    void dfs2(int u,int t) {
        top[u] = t;
        id[u] = ++_tot;
        if (son[u]) dfs2(son[u], t);
        for (int i = 0; i < G[u].size(); i++) {
            int v = G[u][i];
            if (v == son[u]) continue;
            ///轻链的下端点top等于它自己
            dfs2(v,v);
        }
    }
    
    int solve(int u, int v) {
        int tu = top[u], tv = top[v];
        while (tu != tv) {
            if (dep[tu] < dep[tv]) {
                swap(tu, tv);
                swap(u, v);
            }
            u = fat[tu];
            tu = top[u];
        }
        return dep[u]>dep[v]?v:u;
    }
    
    void init() {
        for (int i = 0; i <= n; i++) G[i].clear();
        for(int i=0; i<=n; i++) fat[i]=-1;
        _tot = 0;
    }
    
    int main() {
        int tc;
        scf("%d",&tc);
        while(tc--) {
            scf("%d",&n);
            init();
            rep(i,0,n-1) {
                int u,v;
                scf("%d%d",&u,&v);
                G[u].pb(v);
                fat[v]=u;
            }
            int rt=0;
            for(int i=1;i<=n;i++){
                if(fat[i]==-1){
                    rt=i; break;
                }
            }
    
            dfs(rt,1);
            dfs2(rt,rt);
    
            int qu,qv;
            scf("%d%d",&qu,&qv);
            prf("%d
    ",solve(qu,qv));
    
        }
        return 0;
    }
    View Code
  • 相关阅读:
    python+requests+re匹配抓取猫眼上映电影信息
    Qt 5.12 LTS 部署
    Apache 日志记录相关设置
    php curl 相关知识
    Apache缓存相关配置
    Apache开启GZIP 压缩网页
    Apache 相关 mod_rewrite ,RewriteCond,{HTTP_HOST}
    Andriod you must restart adb and eclipse
    JDK 环境变量的配置
    http 协议详解
  • 原文地址:https://www.cnblogs.com/fenice/p/5385192.html
Copyright © 2011-2022 走看看