P2597 [ZJOI2012]灾难【支配树】
2019-07-30 20:31
78 查看
题目链接
这是一道支配树的模板题了,然后写一下我初见支配树的理解。
第一次碰到支配树是在昨天的多校第三场的1002,当时我推了个拓扑排序加上LCA的求差( dp[a] + dp[b] - dp[lca(a, b)] )来解这个问题,然后为了处理出来每个的dp值,我想到的方法就是用并查集加上拓扑排序的维护,结果,没有维护好,就没有过样例了,尴尬。
后来知道了昨天的这个问题的正解是支配树,然后就开始学习了这个新的知识。
支配树解决什么问题呢?就是解决从s起点到t终点的必经之点有哪几个。刚好也是我那时候所要的东西了。
然后这道题呢,是一个以食物链作为背景的这样一个问题,如果食物链上的某个物种灭绝,会影响到多少其他的物种?
那么,不就是个很纯粹的支配树的问题了吗?我们要求的支配点,不就是从任意一点到祖先链上的必经点的数量了吗?
支配树的建立标准是怎样的呢?做了这道题的思路就是我们把每个点连到它的最近的支配点(必经点)上去,然后这样就可以累加了,就相当于是在处理一个树的子节点的和问题了。并且由于这是个DAG的图,所以不会存在环,我们可以保证最后加上超级源点0的图一定是一棵完整的支配树。
步骤:
(1)、拓扑排序;
(2)、根据LCA,求每个点的最近必经点的位置。这里由于是拓扑排序过的,所以就保证了这个序列上的一定是从树根往树枝上去的;
(3)、建立支配树。
[code]#include <iostream> #include <cstdio> #include <cmath> #include <string> #include <cstring> #include <algorithm> #include <limits> #include <vector> #include <stack> #include <queue> #include <set> #include <map> #define lowbit(x) ( x&(-x) ) #define pi 3.141592653589793 #define e 2.718281828459045 #define INF 0x3f3f3f3f #define HalF (l + r)>>1 #define lsn rt<<1 #define rsn rt<<1|1 #define Lson lsn, l, mid #define Rson rsn, mid+1, r #define QL Lson, ql, qr #define QR Rson, ql, qr #define myself rt, l, r #define MP(x, y) make_pair(x, y) using namespace std; typedef unsigned long long ull; typedef long long ll; const int maxN = 65540; int N, du[maxN], tpsort[maxN], tp, siz[maxN], root[maxN][18], deep[maxN]; vector<int> g[maxN], rg[maxN], ng[maxN]; queue<int> Q; inline void tuopu() { for(int i=1; i<=N; i++) if(!du[i]) { Q.push(i); g[0].push_back(i); rg[i].push_back(0); } tpsort[++tp] = 0; while(!Q.empty()) { int u = Q.front(); Q.pop(); tpsort[++tp] = u; int len = (int)g[u].size(); for(int i=0, v; i<len; i++) { v = g[u][i]; du[v]--; if(!du[v]) Q.push(v); } } } inline int _lca(int u, int v) { if(deep[u] < deep[v]) swap(u, v); int tmp = deep[u] - deep[v]; for(int i=log2(1. * tmp); i>=0; i--) { if((1<<i) & tmp) u = root[u][i]; } if(u == v) return u; for(int i=log2(1. * N); i>=0; i--) { if(root[u][i] != root[v][i]) { u = root[u][i]; v = root[v][i]; } } return root[u][0]; } void dfs(int u) { siz[u] = 1; int len = (int)ng[u].size(); for(int i=0, v; i<len; i++) { v = ng[u][i]; dfs(v); siz[u] += siz[v]; } } int main() { scanf("%d", &N); for(int i=1, x; i<=N; i++) { scanf("%d", &x); while(x) { g[x].push_back(i); rg[i].push_back(x); du[i]++; scanf("%d", &x); } } tuopu(); for(int u=2, x; u<=tp; u++) { x = tpsort[u]; int len = (int)rg[x].size(), y = rg[x][0]; for(int i=1, v; i<len; i++) { v = rg[x][i]; y = _lca(y, v); } ng[y].push_back(x); deep[x] = deep[y] + 1; root[x][0] = y; for(int i=0; i<=log2(1. * N); i++) root[x][i + 1] = root[root[x][i]][i]; } dfs(0); for(int i=1; i<=N; i++) printf("%d\n", siz[i] - 1); return 0; } /* 6 0 1 0 1 0 1 0 3 0 2 4 5 0 ans:5 0 1 0 0 0 */
相关文章推荐
- Lengauer-Tarjan算法--支配树构造(bzoj 2815: [ZJOI2012]灾难)
- P2597 [ZJOI2012]灾难(top+lca)
- bzoj 2815: [ZJOI2012]灾难 支配树
- [BZOJ 2815][ZJOI 2012] 灾难 LCA+拓扑排序(支配树)
- 洛谷 P2597 [ZJOI2012]灾难(拓扑排序+建树+动态LCA+树上前缀和)
- P2597 [ZJOI2012]灾难
- 洛谷 P2597 [ZJOI2012]灾难 灭绝树
- BZOJ 2815 [ZJOI2012]灾难 (支配树)拓扑+倍增
- zjoi2012灾难
- [BZOJ2815][ZJOI2012]灾难 拓扑排序+lca
- BZOJ_2815_[ZJOI2012]灾难 倍增lca + 构造
- BZOJ2815: [ZJOI2012]灾难
- bzoj2815: [ZJOI2012]灾难
- 【bzoj2851】【ZJOI2012】【灾难】【LCA】
- BZOJ2815 ZJOI2012 灾难
- BZOJ 2815 [ZJOI2012]灾难【灭绝树
- BZOJ 2815 ZJOI 2012 灾难 动态倍增LCA
- 【ZJOI2012】【BZOJ2815】灾难 (catas) {拓扑+倍增lca}
- 【BZOJ】2815: [ZJOI2012]灾难
- 1321. [ZJOI2012] 灾难