【洛谷 P2597】 [ZJOI2012]災難(LCA)

題目鏈接
考慮建一棵樹,使一個生物滅絕時他的子樹都會滅絕,顯然這樣答案就是以每個點爲根的子樹大小-1.
爲什麼原圖不是一棵樹,因爲一個生物可能會以多個生物爲食,所以按拓撲序來建樹,把每個遍歷到的點的父親設爲它的所有食物的\(LCA\)
因爲是按拓撲序來的,所以當遍歷到這個生物時,它的所有食物肯定是已經在樹中的。

#include <cstdio>
#include <queue>
#define Open(s) freopen(s".in","r",stdin);freopen(s".out","w",stdout);
using namespace std;
const int MAXN = 100010;
struct Edge{
    int next, to;
};
struct edge{
    Edge e[MAXN << 4];
    int head[MAXN], num;
    inline void Add(int from, int to){
        e[++num] = (Edge){ head[from], to }; head[from] = num;
    }
}S, T, P;
int n, in[MAXN], IN[MAXN], dep[MAXN], size[MAXN], f[MAXN][20], a;
queue <int> q;
inline int LCA(int u, int v){
    if(dep[u] > dep[v]) swap(u, v);
    int cha = dep[v] - dep[u];
    if(cha)
        for(int i = 0; i <= 19; ++i)
            if((cha >> i) & 1)
                v = f[v][i];
    if(u == v) return u;
    for(int i = 19; ~i; --i)
        if(f[u][i] != f[v][i])
            u = f[u][i], v = f[v][i];
    return f[u][0];
}
int main(){
    scanf("%d", &n);
    for(int i = 1; i <= n; ++i)
        while(scanf("%d", &a) && a) S.Add(a, i), ++in[i], T.Add(i, a);
    for(int i = 1; i <= n; ++i) if(!in[i]) q.push(i);
    while(q.size()){
        int now = q.front(); q.pop();
        int p = T.e[T.head[now]].to;
        for(int i = T.e[T.head[now]].next; i; i = T.e[i].next)
            p = LCA(p, T.e[i].to);
        P.Add(now, p); f[now][0] = p; dep[now] = dep[p] + 1; ++IN[p];
        for(int i = 1; i <= 17; ++i)
            f[now][i] = f[f[now][i - 1]][i - 1];
        for(int i = S.head[now]; i; i = S.e[i].next)
            if(!(--in[S.e[i].to]))
                q.push(S.e[i].to);
    }
    for(int i = 1; i <= n; ++i)
        if(!IN[i])
            q.push(i);
    while(q.size()){
        int now = q.front(); q.pop();
        for(int i = P.head[now]; i; i = P.e[i].next){
            size[P.e[i].to] += size[now] + 1;
            if(!(--IN[P.e[i].to]))
                q.push(P.e[i].to);
        }
    }
    for(int i = 1; i <= n; ++i)
        printf("%d\n", size[i]);
    return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章