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;    
}
原文地址:https://www.cnblogs.com/Lyush/p/3083915.html