[日常训练]大灾难
Posted Aireen Ye
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[日常训练]大灾难相关的知识,希望对你有一定的参考价值。
Description
在一个生态圈中,食物链的维系是很重要的。食物链的断裂往往引起连锁反应,进而招致生态系统如同多米诺骨牌一样坍塌。
现在考虑一个简化模型。在一个生态系统中,有$N$种生物,它们分为两类:生产者与消费者。生产者通过这个系统之外的能量来生存,最常见的是植物的光合作用。而消费者需要“消费”,也就是以其他生物为食物才可以生存。为了简化问题,我们假设所有消费者是可以分层的,高一层的消费者可能的食物来源都来自它的严格下层。生产者可以视为最下层的成员。当一种生物灭绝之后,依赖于它的消费者会由于所有食物消失而灭绝。 而这些消费者的灭绝可能进一步引起它的上层成员灭绝。我们定义指标$C(x)$,用于表示当x从生态系统中消失之后,随它灭绝的生物数量。
给定一个食物链模型,对所有生物,计算它的灭绝指标$C(x)$。
Input
第一行一个整数$N,表示生物的数量。生物从$1$开始编号。
接下来$N$行,第$i$行表示第$i$种生物的食物列表。两种食物的编号以空格隔开,输入$0$表示本行结束。如果这一行只有一个$0$,这是一个生产者,不能认为它没有食物而天然灭绝。
Output
共$N$行,第$i$行是第$i$个生物的灭绝指标$C(i)$。
Sample Input
5
0
1 0
1 0
2 3 0
2 0
Sample Output
4 1 0 0 0
HINT
$N\;\leq\;65534$,输入保证合法(即可以分层)。输入文件大小不超过$1MB$。
Solution
显然,整张食物网是$DAG$.
利用$topo$序将图分层.
一个物种会灭亡当且仅当它的所有食物的公共祖先灭亡.
建树,每个物种的所有食物的公共祖先向每个物种连一条边,求子树大小.
#include<cmath> #include<ctime> #include<queue> #include<stack> #include<cstdio> #include<vector> #include<cstring> #include<cstdlib> #include<iostream> #include<algorithm> #define K 17 #define N 65535 #define M 300000 using namespace std; struct graph{ int nxt,to; }e[N<<1],e1[M],e2[M]; struct lives{ int n,dep; }a[N]; int f[N][K],t[N],g[N],g1[N],g2[N],dep[N],siz[N],n,cnt,tot; queue<int> q; inline void adde1(int x,int y){ e1[++cnt].nxt=g1[x];g1[x]=cnt;e1[cnt].to=y; } inline void adde2(int x,int y){ e2[++tot].nxt=g2[x];g2[x]=tot;e2[tot].to=y; } inline void addedge(int x,int y){ e[++cnt].nxt=g[x];g[x]=cnt;e[cnt].to=y; } inline bool cmp(lives x,lives y){ return x.dep<y.dep; } inline void toposort(){ int u; for(int i=1;i<=n;++i) if(!t[i]) q.push(i); while(!q.empty()){ u=q.front();q.pop();a[u].dep=++tot; for(int i=g1[u];i;i=e1[i].nxt) if(!(--t[e1[i].to])) q.push(e1[i].to); } } inline void dfs(int u){ siz[u]=1; for(int i=g[u];i;i=e[i].nxt){ dfs(e[i].to);siz[u]+=siz[e[i].to]; } } inline int swim(int x,int h){ for(int i=0;h;++i,h>>=1) if(h&1) x=f[x][i]; return x; } inline int lca(int x,int y){ int i,t; if(dep[x]<dep[y]){ t=x;x=y;y=t; } x=swim(x,dep[x]-dep[y]); if(x==y) return x; while(true){ for(i=0;f[x][i]!=f[y][i];++i); if(!i) return f[x][0]; x=f[x][i-1];y=f[y][i-1]; } } inline void Aireen(){ scanf("%d",&n); for(int i=1,k;i<=n;++i){ while(true){ scanf("%d",&k); if(!k) break; adde1(k,i);++t[i];adde2(i,k); } } tot=cnt=0;toposort(); for(int i=1;i<=n;++i) a[i].n=i; sort(a+1,a+1+n,cmp); for(int q=1,i,j,l;q<=n;++q){ i=a[q].n;j=g2[i]; if(j){ l=e2[j].to; for(j=e2[j].nxt;j;j=e2[j].nxt) l=lca(e2[j].to,l); addedge(l,i); f[i][0]=l; for(int k=1;k<K;++k) f[i][k]=f[f[i][k-1]][k-1]; dep[i]=dep[l]+1; } else{ addedge(0,i); for(int k=0;k<K;++k) f[i][k]=0; dep[i]=1; } } dfs(0); for(int i=1;i<=n;++i) printf("%d\n",siz[i]-1); } int main(){ freopen("catas.in","r",stdin); freopen("catas.out","w",stdout); Aireen(); fclose(stdin); fclose(stdout); return 0; }
以上是关于[日常训练]大灾难的主要内容,如果未能解决你的问题,请参考以下文章
Tableau server日常维护 17处理Tableau server 灾难性恢复
译文:18个实用的JavaScript代码片段,助你快速处理日常编程任务