bzoj2815灾难[ZJOI2012](拓扑排序+lca)
Posted QuartZ_Z
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了bzoj2815灾难[ZJOI2012](拓扑排序+lca)相关的知识,希望对你有一定的参考价值。
题目传送门:http://www.lydsy.com/JudgeOnline/problem.php?id=2815
原版题解:http://fanhq666.blog.163.com/blog/static/8194342620124274154996/
首先这个生态系统里可能有多个生产者,所以我们可以让生产者吃一种构造出来的食物——阳光。
这道题的图没有环(不然还怎么叫食物网),所以我们可以用拓扑排序把从阳光到各级消费者的先后顺序求出来。
我们可以建出一个结构(可以证明这个结构是一棵树),生物x会因为生物y的灭绝而灭绝,当且仅当y是x的祖先。
因此,如果一种生物会灭绝,只能是因为它的所有食物的lca灭绝了,否则至少有一种食物不会灭绝,这种生物也能活下去,所以这种生物在树上的位置就是它所有食物的lca的孩子。
然后我们把树建出来之后每个节点的答案就是以他为根的子树的节点个数-1。
代码:
#include<cstdio> #include<cstring> #include<cmath> #include<cstdlib> #include<ctime> #include<algorithm> #include<queue> #include<vector> #define ll long long ll read() { ll tmp=0; char f=1,c=getchar(); while(c<‘0‘||‘9‘<c){if(c==‘-‘)f=-1; c=getchar();} while(‘0‘<=c&&c<=‘9‘){tmp=tmp*10+c-‘0‘; c=getchar();} return tmp*f; } using namespace std; int fir[70010]={0},ne[1000010],to[1000010],x[1000010],y[1000010]; int q[70010],vis[70010]={0}; ll in[70010]={0},cnt[70010]; int fa[70010][20],dep[70010]; int n,m,tot=0; void add(int x,int y){to[++tot]=y; ne[tot]=fir[x]; fir[x]=tot;} int lca(int x,int y) { int i; if(dep[x]<dep[y]){int tmp=x; x=y; y=tmp;} for(i=(int)(log(n)/log(2)+1);i>=0;i--)if(dep[x]-(1<<i)>=dep[y])x=fa[x][i]; if(x==y)return x; for(i=(int)(log(n)/log(2)+1);i>=0;i--)if(fa[x][i]!=fa[y][i])x=fa[x][i],y=fa[y][i]; return fa[x][0]; } int main() { int i,j; n=read(); for(i=1;i<=n;i++){ int k=read(); if(!k)add(0,i),in[i]=1,x[tot]=i,y[tot]=0; while(k){++in[i]; add(k,i); x[tot]=i; y[tot]=k; k=read();} } int h=0,t=0; q[0]=0; vis[0]=1; while(h<=t){ for(i=fir[q[h]];i;i=ne[i]){ --in[to[i]]; if(!in[to[i]])q[++t]=to[i],in[to[i]]=1<<30; } ++h; } m=tot; tot=0; for(i=1;i<=n;i++)fir[i]=0; for(i=1;i<=m;i++)add(x[i],y[i]); for(i=0;i<=n;i++) for(j=0;1<<j<=n;j++) fa[i][j]=-1; fa[0][0]=-1; dep[0]=0; for(i=1;i<=n;i++){ int p=-1; for(j=fir[q[i]];j;j=ne[j]) if(p==-1)p=to[j];else p=lca(p,to[j]); fa[q[i]][0]=p; dep[q[i]]=dep[p]+1; for(j=1;1<<j<=n&&fa[fa[q[i]][j-1]][j-1]>=0;j++)fa[q[i]][j]=fa[fa[q[i]][j-1]][j-1]; } for(i=1;i<=n;i++)cnt[i]=1; for(i=n;i;i--)cnt[fa[q[i]][0]]+=cnt[q[i]]; for(i=1;i<=n;i++) printf("%lld\n",cnt[i]-1); }
以上是关于bzoj2815灾难[ZJOI2012](拓扑排序+lca)的主要内容,如果未能解决你的问题,请参考以下文章