题目描述
在一个生态圈中,食物链的维系是很重要的。食物链的断裂往往引起连锁反应,进而招致生态系统如同多米诺骨牌一样坍塌。
现在考虑一个简化模型。在一个生态系统中,有N 种生物,它们分为两类:生产者与消费者。生产者通过这个系统之外的能量来生存,最常见的是植物的光合作用。而消费者需要“消费”,也就是以其他生物为食物才可以生存。为了简化问题,我们假设所有消费者是可以分层的,高一层的消费者可能的食物来源都来自它的严格下层。生产者可以视为最下层的成员。
当一种生物灭绝之后,依赖于它的消费者会由于所有食物消失而灭绝。
而这些消费者的灭绝可能进一步引起它的上层成员灭绝。我们定义指标C(x),用于表示当x 从生态系统中消失之后,随它灭绝的生物数量。给定一个食物链模型,对所有生物,计算它的灭绝指标C(x)。
输入格式
第一行一个整数N,表示生物的数量。生物从1 开始编号。
接下来N 行,第i 行表示第i 种生物的食物列表。两种食物的编号以空格隔开,输入0 表示本行结束。如果这一行只有一个0,这是一个生产者,不能认为它没有食物而天然灭绝。
输出格式
共N 行,第i 行是第i 个生物的灭绝指标C(i)。
样例
样例输入
5
0
1 0
1 0
2 3 0
2 0
样例输出
4
1
0
0
0
数据范围与提示
【样例解释】
1 号生物是唯一的生产者。它的灭绝将导致所有生物灭绝。
2 号与3 号生物位于食物链的次下层。2 号的灭绝将导致5 号的所有食物消失从而灭绝,但不会有其他效果。
4 号与5 号位于食物链的最上层。它们的灭绝不会改变食物链下层的格局。
【数据范围】
对于50% 的数据,N <= 10000
对于100% 的数据,N <= 65534,输入保证合法(即可以分层)
输入文件大小不超过1MB
来源
2015福建冬令营day4
显示分类标签
题解:
首先,可知当且仅当所有食物全部灭绝时,当前的生物才会灭绝。
假如我们知道当哪个生物灭绝时,所有食物都会全部灭绝,那当前生物对能让这个生物灭绝的都有贡献,所以考虑维护一个灭绝树。
把当前生物的父亲为灭绝树中所有食物的LCA,表示只有父亲灭绝他才能灭绝。
建树的顺序按拓扑序。
#include<iostream>
#include<cstring>
#include<cstdio>
#include<cmath>
#include<algorithm>
#include<queue>
#include<vector>
#define N 70005
using namespace std;
int head[N],ver[N<<3],nex[N<<3];
int tot;int T,f[N][20],ru[N],dep[N];
int vh[N],vv[N<<2],vn[N<<2],vt,size[N],n;
vector<int> food[N];
inline int read()
{
char $;int u;
while(($=getchar())>57||$<48);u=$-'0';
while(($=getchar())>47&&$<58)u+=u+(u<<3)+$-48;
return u;
}
inline void add(int x,int y){
nex[++tot]=head[x];head[x]=tot;ver[tot]=y;ru[y]++;
}
inline void v_add(int x,int y){
vn[++vt]=vh[x];vh[x]=vt;vv[vt]=y;
}
int get_lca(int x,int y){
if(dep[x]>dep[y])swap(x,y);
for(int i=T;i+1;--i)if(dep[f[y][i]]>=dep[x])y=f[y][i];
if(x==y)return x;
for(int i=T;i+1;--i)if(f[y][i]!=f[x][i])y=f[y][i],x=f[x][i];
return f[x][0];
}
void Link(int x){
int lca=food[x][0];
for(int i=1;i<food[x].size();++i){
lca=get_lca(lca,food[x][i]);
}
f[x][0]=lca;dep[x]=dep[lca]+1;
v_add(lca,x);
// cout<<x<<" "<<lca<<endl;
for(int i=1;i<=T;++i){
f[x][i]=f[f[x][i-1]][i-1];
}
}
void toposort(){
queue<int> q;
q.push(n+1);dep[n+1]=1;
while(!q.empty()){
int x=q.front();q.pop();
if(x!=n+1)Link(x);
for(int i=head[x];i;i=nex[i]){
ru[ver[i]]--;
if(!ru[ver[i]])q.push(ver[i]);
}
}
}
void dfs(int x){
size[x]=1;
for(int i=vh[x];i;i=vn[i]){
int y=vv[i];
dfs(y);
size[x]+=size[y];
}
}
int main(){
n=read();
for(int i=1;i<=n;++i){
int x=0;x=read();
while(x!=0){
food[i].push_back(x);
x=read();
}
if(food[i].empty())food[i].push_back(n+1);
}
for(int i=1;i<=n;++i){
for(int j=0;j<food[i].size();++j){
add(food[i][j],i);
}
}
T=(double)log(n*1.0)/log(2);
toposort();
dfs(n+1);
for(int i=1;i<=n;++i)cout<<size[i]-1<<endl;
return 0;
}