首页 > 其他 > 详细

[ZJOI2012]灾难

时间:2019-03-10 19:30:02      阅读:148      评论:0      收藏:0      [点我收藏+]

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]灾难

原文:https://www.cnblogs.com/list1/p/10506496.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!