[ZJOI2012]災難
阿新 • • 發佈:2019-03-10
void dfs ret set %d zjoi2012 wap oid clu
Description:
一個食物網有N個點,代表N種生物,如果生物x可以吃生物y,那麽從y向x連一個有向邊。
這個圖沒有環。
圖中有一些點沒有連出邊,這些點代表的生物都是生產者,可以通過光合作用來生存; 而有連出邊的點代表的都是消費者,它們必須通過吃其他生物來生存。
如果某個消費者的所有食物都滅絕了,它會跟著滅絕。
我們定義一個生物在食物網中的“災難值”為,如果它突然滅絕,那麽會跟著一起滅絕的生物的種數。
舉個例子:在一個草場上,生物之間的關系是:
如果小強和阿米巴把草原上所有的羊都給嚇死了,那麽狼會因為沒有食物而滅絕,而小強和阿米巴可以通過吃牛、牛可以通過吃草來生存下去。所以,羊的災難值是1。但是,如果草突然滅絕,那麽整個草原上的5種生物都無法幸免,所以,草的災難值是4。
給定一個食物網,你要求出每個生物的災難值。
Hint:
\(n \le 5*10^4\)
Solution:
不是很難的一道題,但為什麽自己不往LCA那方面想呢
一個物種如果滅絕,則它的所有父親都必須滅絕
假設我們這個點以上是一棵樹,那這些父親的LCA必須滅絕
同時把該節點給接到那個LCA上,這樣一定是對的,並且維護了這棵樹
按拓撲序這樣逐步操作,最終形成一棵樹,直接dfs算答案
要註意建新圖,同時開一個虛點連接入度為0的點
#include <map> #include <set> #include <stack> #include <cmath> #include <queue> #include <cstdio> #include <cstring> #include <cstdlib> #include <iostream> #include <algorithm> #define ls p<<1 #define rs p<<1|1 using namespace std; typedef long long ll; const int mxn=5e4+5; int n,cnt,tot,hd[mxn],rk[mxn],sz[mxn],in[mxn],hd2[mxn],tag[mxn],dep[mxn]; int f[mxn][19]; vector <int > fa[mxn]; queue <int > q; inline int read() { char c=getchar(); int x=0,f=1; while(c>'9'||c<'0') {if(c=='-') f=-1;c=getchar();} while(c<='9'&&c>='0') {x=(x<<3)+(x<<1)+(c&15);c=getchar();} return x*f; } inline int chkmax(int &x,int y) {if(x<y) x=y;} inline int chkmin(int &x,int y) {if(x>y) x=y;} struct ed { int to,nxt; }t[mxn<<1],t2[mxn<<1]; inline void add(int u,int v) { t[++cnt]=(ed) {v,hd[u]}; hd[u]=cnt; } inline void add2(int u,int v) { t2[++cnt]=(ed) {v,hd2[u]}; hd2[u]=cnt; } void topo() { for(int i=1;i<=n;++i) if(in[i]==0) q.push(i),tag[i]=1; while(!q.empty()) { int u=q.front(); rk[++tot]=u; q.pop(); for(int i=hd[u];i;i=t[i].nxt) { int v=t[i].to; --in[v]; if(in[v]==0) q.push(v); } } } int lca(int x,int y) { if(dep[x]<dep[y]) swap(x,y); for(int i=18;i>=0;--i) if(dep[f[x][i]]>=dep[y]) x=f[x][i]; if(x==y) return x; for(int i=18;i>=0;--i) if(f[x][i]!=f[y][i]) x=f[x][i],y=f[y][i]; return f[x][0]; } void solve() { for(int i=1;i<=tot;++i) { int w,z; w=z=rk[i]; if(tag[w]) { add2(0,w); dep[w]=1; continue ; } for(int j=0;j<fa[z].size();++j) { int v=fa[z][j]; if(j==0) w=v; w=lca(w,v); } f[z][0]=w,add2(w,z),dep[z]=dep[w]+1; for(int j=1;j<=18;++j) f[z][j]=f[f[z][j-1]][j-1]; } } void dfs(int u) { sz[u]=1; for(int i=hd2[u];i;i=t2[i].nxt) { int v=t2[i].to; dfs(v); sz[u]+=sz[v]; } } int main() { n=read(); int x; for(int i=1;i<=n;++i) { while((x=read())!=0) { add(x,i); ++in[i]; fa[i].push_back(x); } } topo(); solve(); dfs(0); for(int i=1;i<=n;++i) printf("%d\n",sz[i]-1); return 0; }
[ZJOI2012]災難