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

[ZJOI2012]災難

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]災難