[BZOJ2815][ZJOI2012]灾难(拓扑排序+LCA)

来源:互联网 发布:小程序第三方平台源码 编辑:程序博客网 时间:2024/05/21 09:26

可以想到建一棵灭绝树(森林),也就是说一个节点灭绝后它的子树灭绝。怎么建呢?
由于原图没有环,所以可以想到根据拓扑序建树。对于没有入度的点,直接作为根节点,对于剩下的点,假设现在考虑到了点u,并且点u之前的灭绝树已经建好,此时考虑点u应该作为哪个节点的子节点。可以想到,节点u灭绝,当且仅当节点u的所有食物的LCA灭绝,所以,求出节点u的所有食物的LCAv之后,就可以把v作为u的父亲,并初始化u的倍增数组(倍增LCA支持添加叶子节点)。
建树后,每个节点的size1就是该节点的灾难值。
代码:

#include <cmath>#include <cstdio>#include <cstring>#include <iostream>#include <algorithm>using namespace std;inline int read() {    int res = 0; bool bo = 0; char c;    while (((c = getchar()) < '0' || c > '9') && c != '-');    if (c == '-') bo = 1; else res = c - 48;    while ((c = getchar()) >= '0' && c <= '9')        res = (res << 3) + (res << 1) + (c - 48);    return bo ? ~res + 1 : res;}const int N = 7e4 + 5, M = 1e6 + 5, LogN = 22;int n, ecnt, nxt[M], adj[N], go[M], ecnt2, nxt2[M], adj2[N], go2[M],ecnt3, nxt3[M], adj3[N], go3[M], dep[N], fa[N][LogN], H, T, Q[M], cnt[N],cnt2[N], sze[N];void add_edge(int u, int v) {    nxt[++ecnt] = adj[u]; adj[u] = ecnt; go[ecnt] = v;}void add_edge2(int u, int v) {    nxt2[++ecnt2] = adj2[u]; adj2[u] = ecnt2; go2[ecnt2] = v;}void add_edge3(int u, int v) {    nxt3[++ecnt3] = adj3[u]; adj3[u] = ecnt3; go3[ecnt3] = v;}int lca(int u, int v) {    int i, x; if (dep[u] < dep[v]) swap(u, v);    x = dep[u] - dep[v];    for (i = 20; i >= 0; i--)        if ((x >> i) & 1) u = fa[u][i];    if (u == v) return u;    for (i = 20; i >= 0; i--)        if (fa[u][i] != fa[v][i])            u = fa[u][i], v = fa[v][i];    return fa[u][0];}void topo() {    int i; H = T = 0;    for (i = 1; i <= n; i++) if (!cnt[i]) Q[++T] = i;    while (H < T) {        int u = Q[++H], tmp = go2[adj2[u]];        for (int e = adj2[u]; e; e = nxt2[e])            tmp = lca(tmp, go2[e]); dep[u] = dep[fa[u][0] = tmp] + 1;        for (i = 0; i <= 19; i++)            fa[u][i + 1] = fa[fa[u][i]][i];        if (tmp) add_edge3(tmp, u), cnt2[u]++;        for (int e = adj[u], v; e; e = nxt[e])            if (!(--cnt[v = go[e]])) Q[++T] = v;    }}void dfs2(int u) {    sze[u] = 1; for (int e = adj3[u]; e; e = nxt3[e])        dfs2(go3[e]), sze[u] += sze[go3[e]];}void solve() {    topo(); int i; for (i = 1; i <= n; i++)        if (!cnt2[i]) dfs2(i);    for (i = 1; i <= n; i++) printf("%d\n", sze[i] - 1);}int main() {    int i, x; n = read();    for (i = 1; i <= n; i++)        while (x = read()) add_edge(x, i), add_edge2(i, x),            cnt[i]++; solve();    return 0;}
阅读全文
0 0
原创粉丝点击