[bzoj2815] [洛谷P2597] [ZJOI2012] 灾难
Description
阿米巴是小强的好朋友。
阿米巴和小强在草原上捉蚂蚱。小强突然想,如果蚂蚱被他们捉灭绝了,那么吃蚂蚱的小鸟就会饿死,而捕食小鸟的猛禽也会跟着灭绝,从而引发一系列的生态灾难。
学过生物的阿米巴告诉小强,草原是一个极其稳定的生态系统。如果蚂蚱灭绝了,小鸟照样可以吃别的虫子,所以一个物种的灭绝并不一定会引发重大的灾难。
我们现在从专业一点的角度来看这个问题。我们用一种叫做食物网的有向图来描述生物之间的关系:
一个食物网有N个点,代表N种生物,如果生物x可以吃生物y,那么从y向x连一个有向边。
这个图没有环。
图中有一些点没有连出边,这些点代表的生物都是生产者,可以通过光合作用来生存; 而有连出边的点代表的都是消费者,它们必须通过吃其他生物来生存。
如果某个消费者的所有食物都灭绝了,它会跟着灭绝。
我们定义一个生物在食物网中的“灾难值”为,如果它突然灭绝,那么会跟着一起灭绝的生物的种数。
举个例子:在一个草场上,生物之间的关系是:
如果小强和阿米巴把草原上所有的羊都给吓死了,那么狼会因为没有食物而灭绝,而小强和阿米巴可以通过吃牛、牛可以通过吃草来生存下去。所以,羊的灾难值是1。但是,如果草突然灭绝,那么整个草原上的5种生物都无法幸免,所以,草的灾难值是4。
给定一个食物网,你要求出每个生物的灾难值。
Input
输入文件 catas.in 的第一行是一个正整数 N,表示生物的种数。生物从 1 标号到 N。
接下来 N 行,每行描述了一个生物可以吃的其他生物的列表,格式为用空
格隔开的若干个数字,每个数字表示一种生物的标号,最后一个数字是 0 表示列表的结束。
Output
输出文件catas.out包含N行,每行一个整数,表示每个生物的灾难值。
Sample Input
5
0
1 0
1 0
2 3 0
2 0
Sample Output
4
1
0
0
0
HINT
【样例说明】
样例输入描述了题目描述中举的例子。
【数据规模】
对50%的数据,N ≤ 10000。
对100%的数据,1 ≤ N ≤ 65534。
输入文件的大小不超过1M。保证输入的食物网没有环。
想法
这道题还比较友好。
我们可以根据食物链建一棵树,每个点的fa为第一个消灭后会使该点灭亡的点
按照拓扑排序的顺序,将每个点加入树中,这个点的fa即为树上所有可被它吃的点的lca
树建完后,dfs一遍求出所有点的子树大小(包括自己)sum[i],sum[i]-1便是答案
感觉这种方法特别好理解有木有。。可是我就是不知道这是怎么想出来的qwq
代码
#include<cstdio> #include<iostream> #include<algorithm> #include<cstring>#define P 1000000007using namespace std;const int N = 70005;struct node{int v;node *next; }pool[N*4],*h[N]; int cnt; void addedge(int u,int v){node *p=&pool[++cnt];p->v=v;p->next=h[u];h[u]=p; }int n; int in[N],fa[N],f[N][20],dep[N],que[N];int lca(int x,int y){if(dep[x]<dep[y]) swap(x,y);for(int i=19;i>=0;i--)if(dep[f[x][i]]>=dep[y]) x=f[x][i];if(x==y) return x;for(int i=19;i>=0;i--)if(f[x][i]!=f[y][i]) x=f[x][i],y=f[y][i];return fa[x]; } void topo(){int head=0,tail=0,u,v;for(int i=1;i<=n;i++) if(!in[i]) que[tail++]=i;while(head<tail){u=que[head++];if(fa[u]==-1) fa[u]=0;f[u][0]=fa[u]; dep[u]=dep[fa[u]]+1;for(int i=1;i<20;i++) f[u][i]=f[f[u][i-1]][i-1];for(node *p=h[u];p;p=p->next){in[v=p->v]--;if(fa[v]!=-1) fa[v]=lca(fa[v],u);else fa[v]=u;if(!in[v]) que[tail++]=v;}} }int sum[N]; void dfs(int u){int v;sum[u]=1;for(node *p=h[u];p;p=p->next){dfs(v=p->v);sum[u]+=sum[v];} }int main() {int x;scanf("%d",&n);for(int i=1;i<=n;i++)while(scanf("%d",&x) && x){addedge(x,i);in[i]++;}memset(fa,-1,sizeof(fa));topo();for(int i=1;i<=n;i++) h[i]=NULL;cnt=0;for(int i=1;i<=n;i++) addedge(fa[i],i);dfs(0);for(int i=1;i<=n;i++) printf("%d\n",sum[i]-1);return 0; }转载于:https://www.cnblogs.com/lindalee/p/8934151.html
总结
以上是生活随笔为你收集整理的[bzoj2815] [洛谷P2597] [ZJOI2012] 灾难的全部内容,希望文章能够帮你解决所遇到的问题。
- 上一篇: ROS与Arduino学习(三)订阅与发
- 下一篇: 关于使用旋转四元数绕轴旋转θ角度时,使用