1. 程式人生 > >Luogu 2597 [ZJOI2012]災難

Luogu 2597 [ZJOI2012]災難

nlog wap 答案 bzoj ++ lse hide none www.

BZOJ 2815。

解法還是挺巧妙的。

放上寫得很詳細很好懂的題解鏈接 戳這裏。

一個物種$x$如果要滅絕,那麽沿著它的入邊反向走走走,一定可以走到一個點$y$,如果這個點$y$的物種滅絕了,那麽$x$也一定會滅絕。而且,因為一次只能滅絕一個物種,只有滿足這個條件這個物種$x$才會滅絕。

那麽我們可以考慮建立一棵樹,對於一個點$x$,將它能直接導致滅絕的點$y$作為它的直接兒子,然後我們統計一下每一個結點的$siz$再$- 1$就是答案了。

考慮一下如何找到這個走走走之後的關鍵點,因為這張圖滿足$DAG$的性質,我們可以一邊拓撲排序一邊建樹,如果當前從隊列裏面取出了$x$,那麽所有在$x$之前能走到的點一定在我們建的樹裏面了,我們只要在建好的樹上找到所有直接連通$x$的點的$lca$作$x$的父親就可以了。

插點的倍增$lca$,可以直接動態維護出來。

可以建一個超級源點連通所有的連通塊。

時間復雜度$O(nlogn)$。

Code:

技術分享圖片
#include <cstdio>
#include <cstring>
#include <vector>
using namespace std;

const int N = 1e5 + 5;
const int Lg = 20;

int n, rt, tot = 0, head[N];
int q[N], fa[N][Lg], dep[N], deg[N], siz[N];
vector 
<int> G1[N], G2[N]; struct Edge { int to, nxt; } e[N << 1]; inline void add(int from, int to) { e[++tot].to = to; e[tot].nxt = head[from]; head[from] = tot; } inline void read(int &X) { X = 0; char ch = 0; int op = 1; for(; ch > 9 || ch <
0; ch = getchar()) if(ch == -) op = -1; for(; ch >= 0 && ch <= 9; ch = getchar()) X = (X << 3) + (X << 1) + ch - 48; X *= op; } inline void swap(int &x, int &y) { int t = x; x = y; y = t; } inline void prework(int x, int fat) { dep[x] = dep[fat] + 1, fa[x][0] = fat; for(int i = 1; i <= 18; i++) fa[x][i] = fa[fa[x][i - 1]][i - 1]; } inline int getLca(int x, int y) { if(dep[x] < dep[y]) swap(x, y); for(int i = 18; i >= 0; i--) if(dep[fa[x][i]] >= dep[y]) x = fa[x][i]; if(x == y) return x; for(int i = 18; i >= 0; i--) if(fa[x][i] != fa[y][i]) x = fa[x][i], y = fa[y][i]; return fa[x][0]; } inline void topSort() { int l = 0, r = 1; q[1] = rt; prework(rt, 0); for(; l <= r; ) { int x = q[++l], fat = 0, vecSiz = G2[x].size(); for(int i = 0; i < vecSiz; i++) { int y = G2[x][i]; if(!fat) fat = y; else fat = getLca(fat, y); } if(x != rt) add(x, fat), add(fat, x); prework(x, fat); vecSiz = G1[x].size(); for(int i = 0; i < vecSiz; i++) { int y = G1[x][i]; --deg[y]; if(!deg[y]) q[++r] = y; } } } void dfs(int x, int fat) { siz[x] = 1; for(int i = head[x]; i; i = e[i].nxt) { int y = e[i].to; if(y == fat) continue; dfs(y, x); siz[x] += siz[y]; } } int main() { read(n); for(int x, i = 1; i <= n; i++) { for(read(x); x; read(x)) { G1[x].push_back(i); G2[i].push_back(x); ++deg[i]; } } rt = n + 1; for(int i = 1; i <= n; i++) if(!deg[i]) { G1[rt].push_back(i); G2[i].push_back(rt); ++deg[i]; } topSort(); dfs(rt, 0); for(int i = 1; i <= n; i++) printf("%d\n", siz[i] - 1); return 0; }
View Code

Luogu 2597 [ZJOI2012]災難