zoukankan      html  css  js  c++  java
  • POJ1470 Closest Common Ancestors TarjanLCA

    题意:给定一棵树,然后给定若干组询问,问某些点被作为最近公共祖先的次数。

    解法:刚刚一直不知道根在哪里给了出来,后来才发现给定的点一定是按照从层数低的节点指向层数高的节点,因此没有双亲的节点为根节点,然后运行tarjan算法即可。这里刚开始的时候我还想把最后的结果除以2输出,这里没有这个必要,因为两个节点一定有一个先后的遍历顺序,这个顺序保证了只被统计一次。

    代码如下:

    #include <cstdlib>
    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    #include <iostream>
    using namespace std;
    
    struct Edge {
        int v, next;    
    }e[2000], q[1000000];
    int idx, head[905];
    int cnt, link[905];
    int set[905];
    
    void insert(int a, int b, int k) {
        if (k == 1) {
            e[idx].v = b, e[idx].next = head[a];
            head[a] = idx++;
        } else {
            q[cnt].v = b, q[cnt].next = link[a];
            link[a] = cnt++;
        }
    }
    
    int find(int x) {
        return set[x] = x == set[x] ? x : find(set[x]);
    }
    
    int N, tot[905];
    char vis[905];
    
    void tarjan(int u) {
        vis[u] = 1, set[u] = u;
        for (int i = link[u]; ~i; i = q[i].next) {
            int v = q[i].v;
            if (vis[v]) {
            //    printf("%d %d %d\n", u, q[i].v, find(v));
                ++tot[find(v)];
            }
        }
        for (int i = head[u]; ~i; i = e[i].next) {
            int v = e[i].v;
            if (!vis[v]) {
                tarjan(v);
                set[v] = u;
            }
        }
    }
    
    void getint(int &t) {
        char c;
        while (c = getchar(), c < '0' || c > '9') ;
        t = c - '0';
        while (c = getchar(), c >= '0' && c <= '9') {
            t = t * 10 + c - '0';
        }
    } 
    
    int main() {
        int x, f, c, Q, rt;
        while (scanf("%d", &N) != EOF) {
            cnt = idx = 0;
            memset(head, 0xff, sizeof (head));
            memset(link, 0xff, sizeof (link));
            memset(tot, 0, sizeof (tot));
            memset(vis, 0, sizeof (vis));
            for (int i = 0; i < N; ++i) {
                scanf("%d:(%d)", &x, &f);
                for (int j = 0; j < f; ++j) {
                    scanf("%d", &c);
                    vis[c] = 1;
                    insert(x, c, 1), insert(c, x, 1);
                }
            }
            for (int i = 1; i <= N; ++i) {
                if (!vis[i]) {
                    rt = i;
                    break;
                }
            }
            memset(vis, 0, sizeof (vis));
            scanf("%d", &Q);
            for (int i = 0; i < Q; ++i) {
                getint(x), getint(c);
                insert(x, c, 2), insert(c, x, 2);
            }
            tarjan(rt);
            for (int i = 1; i <= N; ++i) {
                if (tot[i]) printf("%d:%d\n", i, tot[i]);
            }
        }
        return 0;    
    }
  • 相关阅读:
    python学习之调试:
    python学习之调试 错误捕捉及处理
    python之面向对象
    python学习之模块:
    python学习之内部函数:
    python学习之高级特性:
    python学习之结构语句
    python学习之列表元组,字典
    getopt使用例子
    找到系统盘被打满文件
  • 原文地址:https://www.cnblogs.com/Lyush/p/3083915.html
Copyright © 2011-2022 走看看