BZOJ2815: [ZJOI2012]灾难

这题挺神仙的

它看上去有一些传递性,感觉要用树做
可是它不是一棵树,考虑把它变成树

对于一个点,它会灭绝当且仅当它的食物都灭绝了

这似乎可以拓扑,但随便想一想就知道是不行的

考虑它的食物都灭绝了满足什么性质

它的食物都灭绝了当且仅当它的食物的食物灭绝了

这样向前是可以追溯到一个点的

这就满足树的关系了,一个点唯一对应一个父亲节点,
他们之间满足:父节点灭绝会导致儿子节点食物灭绝进而使儿子节点灭绝

而这样恰好也满足了题目中让你求的“灾难值”

子树求 size 即可


 代码:

#include <algorithm>
#include <iostream>
#include <cstdlib>
#include <cstring>
#include <cctype>
#include <cstdio>
#include <vector>
#include <queue>
#include <cmath>
using namespace std;
 
const int MAXN = 65540;
 
struct EDGE{
    int nxt, to;
    EDGE(int NXT = 0, int TO = 0) {nxt = NXT; to = TO;}
}edge[MAXN << 1];
int n, totedge, lg;
int head[MAXN], dep[MAXN], ind[MAXN];
int f[MAXN][18], siz[MAXN], com[MAXN];
vector<int> edg[MAXN];
queue<int> q;
 
inline void add(int x, int y) {         //x to y, son to fa
    f[x][0] = y;
    dep[x] = dep[y] + 1;
    edge[++totedge] = EDGE(head[x], y);
    head[x] = totedge;
    edge[++totedge] = EDGE(head[y], x);
    head[y] = totedge;
    return;
}
inline void init(int x) {
    for (int i = 1; i <= lg; ++i) 
        f[x][i] = f[f[x][i - 1]][i - 1];
    return;
}
inline int lca(int x, int y) {
    if (dep[x] < dep[y]) swap(x, y);
    for (int i = lg; i >= 0; --i) 
        if (dep[f[x][i]] >= dep[y]) x = f[x][i];
    if (x == y) return x;
    for (int i = lg; i >= 0; --i) 
        if (f[x][i] != f[y][i]) x = f[x][i], y = f[y][i];
    return f[x][0];
}
void dfs(int x) {
    siz[x] = 1;
    for (int i = head[x]; i; i = edge[i].nxt) if (edge[i].to != f[x][0]) {
        int y = edge[i].to;
        dfs(y);
        siz[x] += siz[y];
    }
    return;
}
 
int main() {
    scanf("%d", &n);
    lg = (int)log2(n) + 1;
    register int xx;
    for (int i = 1; i <= n; ++i) {
        scanf("%d", &xx);
        while (xx) {
            ++ind[i];
            edg[xx].push_back(i);
            scanf("%d", &xx);
        }
    }
    for (int i = 1; i <= n; ++i) {
        com[i] = -1;
        if (!ind[i]) {
            q.push(i);
            com[i] = 0;
        }
    }
    while (!q.empty()) {
        int x = q.front(); q.pop();
        add(x, com[x]);
        init(x);
        for (int i = 0; i < edg[x].size(); ++i) {
            register int y = edg[x][i];
            com[y] = ((~com[y]) ? lca(com[y], x) : x);
            --ind[y];
            if (!ind[y]) q.push(y);
        }
    }
    dfs(0);
    for (int i = 1; i <= n; ++i) printf("%d\n", siz[i] - 1);
    return 0;
}
posted @ 2018-10-19 06:57  EvalonXing  阅读(106)  评论(0编辑  收藏  举报