[BZOJ2815][ZJOI2012]灾难(拓扑排序+LCA)
2017-11-19 11:38
387 查看
可以想到建一棵灭绝树(森林),也就是说一个节点灭绝后它的子树灭绝。怎么建呢?
由于原图没有环,所以可以想到根据拓扑序建树。对于没有入度的点,直接作为根节点,对于剩下的点,假设现在考虑到了点u,并且点u之前的灭绝树已经建好,此时考虑点u应该作为哪个节点的子节点。可以想到,节点u灭绝,当且仅当节点u的所有食物的LCA灭绝,所以,求出节点u的所有食物的LCAv之后,就可以把v作为u的父亲,并初始化u的倍增数组(倍增LCA支持添加叶子节点)。
建树后,每个节点的size减1就是该节点的灾难值。
代码:
由于原图没有环,所以可以想到根据拓扑序建树。对于没有入度的点,直接作为根节点,对于剩下的点,假设现在考虑到了点u,并且点u之前的灭绝树已经建好,此时考虑点u应该作为哪个节点的子节点。可以想到,节点u灭绝,当且仅当节点u的所有食物的LCA灭绝,所以,求出节点u的所有食物的LCAv之后,就可以把v作为u的父亲,并初始化u的倍增数组(倍增LCA支持添加叶子节点)。
建树后,每个节点的size减1就是该节点的灾难值。
代码:
#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 , go[M], ecnt2, nxt2[M], adj2 , go2[M], ecnt3, nxt3[M], adj3 , go3[M], dep , fa [LogN], H, T, Q[M], cnt , cnt2 , sze ; 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; }
相关文章推荐
- 【BZOJ2815】【ZJOI2012】灾难 [LCA]
- BZOJ 2815 ZJOI 2012 灾难 动态倍增LCA
- BZOJ_2815_[ZJOI2012]灾难 倍增lca + 构造
- 【BZOJ2815】【ZJOI2012】灾难 阿米巴和小强题 动态倍增LCA 灾难树
- 【ZJOI2012】【BZOJ2815】灾难 (catas) {拓扑+倍增lca}
- bzoj 2815: [ZJOI2012]灾难|倍增lca|思路题
- [BZOJ2815][ZJOI2012]灾难(倍增lca+top)
- 【bzoj2815】灾难[ZJOI2012](拓扑排序+lca)
- [拓扑+LCA]BZOJ 2815——[ZJOI2012]灾难
- bzoj 2815 [ZJOI2012]灾难(构造,树形DP)
- [BZOJ2815][ZJOI2012]灾难 灭绝树+拓扑排序+lca
- BZOJ2815 [ZJOI2012]灾难
- 树型动态规划练习题:【bzoj2815】[ZJOI2012]灾难
- 【BZOJ2815】灾难(ZJOI2012)-拓扑排序+建树+LCA
- BZOJ 2815 [ZJOI2012]灾难 (支配树)拓扑+倍增
- bzoj 2815: [ZJOI2012]灾难
- 【BZOJ】2815: [ZJOI2012]灾难
- [BZOJ2815][ZJOI2012]灾难 拓扑排序+lca
- BZOJ 2815 [ZJOI2012]灾难【灭绝树
- BZOJ 2815 [ZJOI2012]灾难