[支配树] Bzoj P2815 灾难
题目描述
阿米巴是小强的好朋友。
阿米巴和小强在草原上捉蚂蚱。小强突然想,如果蚂蚱被他们捉灭绝了,那么吃蚂蚱的小鸟就会饿死,而捕食小鸟的猛禽也会跟着灭绝,从而引发一系列的生态灾难。
学过生物的阿米巴告诉小强,草原是一个极其稳定的生态系统。如果蚂蚱灭绝了,小鸟照样可以吃别的虫子,所以一个物种的灭绝并不一定会引发重大的灾难。
我们现在从专业一点的角度来看这个问题。我们用一种叫做食物网的有向图来描述生物之间的关系:
一个食物网有N个点,代表N种生物,如果生物x可以吃生物y,那么从y向x连一个有向边。
这个图没有环。
图中有一些点没有连出边,这些点代表的生物都是生产者,可以通过光合作用来生存; 而有连出边的点代表的都是消费者,它们必须通过吃其他生物来生存。
如果某个消费者的所有食物都灭绝了,它会跟着灭绝。
我们定义一个生物在食物网中的“灾难值”为,如果它突然灭绝,那么会跟着一起灭绝的生物的种数。
举个例子:在一个草场上,生物之间的关系是:
如
如果小强和阿米巴把草原上所有的羊都给吓死了,那么狼会因为没有食物而灭绝,而小强和阿米巴可以通过吃牛、牛可以通过吃草来生存下去。所以,羊的灾难值是1。但是,如果草突然灭绝,那么整个草原上的5种生物都无法幸免,所以,草的灾难值是4。
给定一个食物网,你要求出每个生物的灾难值。
输入输出格式
输入格式:
输入文件 catas.in 的第一行是一个正整数 N,表示生物的种数。生物从 1 标
号到 N。
接下来 N 行,每行描述了一个生物可以吃的其他生物的列表,格式为用空
格隔开的若干个数字,每个数字表示一种生物的标号,最后一个数字是 0 表示列
表的结束。
输出格式:
输出文件catas.out包含N行,每行一个整数,表示每个生物的灾难值。
输入输出样例
说明
【样例说明】
样例输入描述了题目描述中举的例子。
【数据规模】
对50%的数据,N ≤ 10000。
对100%的数据,1 ≤ N ≤ 65534。
输入文件的大小不超过1M。保证输入的食物网没有环。
题解
- 直接把支配树建出来,然后一个点的答案就是它在支配树上的size-1
代码
1 #include <queue> 2 #include <cstdio> 3 #include <cstring> 4 #include <iostream> 5 using namespace std; 6 const int N=100010; 7 int n,cnt,last[N],head[N],a[N],fa[N][20],deep[N],d[N],size[N]; 8 struct edge{int to,from;}e[N*30]; 9 queue<int>Q; 10 void insert(int x,int y) 11 { 12 e[++cnt].to=y,e[cnt].from=head[x],head[x]=cnt; 13 e[++cnt].to=x,e[cnt].from=last[y],last[y]=cnt; 14 } 15 void topusort() 16 { 17 Q.push(n+1); 18 while (!Q.empty()) 19 { 20 int u=Q.front(); Q.pop(),a[++a[0]]=u; 21 for (int i=head[u];i;i=e[i].from) 22 { 23 d[e[i].to]--; 24 if (!d[e[i].to]) Q.push(e[i].to); 25 } 26 } 27 } 28 int getlca(int x,int y) 29 { 30 if (deep[x]<deep[y]) swap(x,y); 31 for (int i=16;i>=0;i--) if (deep[fa[x][i]]>=deep[y]) x=fa[x][i]; 32 if (x==y) return x; 33 for (int i=16;i>=0;i--) if (fa[x][i]!=fa[y][i]) x=fa[x][i],y=fa[y][i]; 34 return fa[x][0]; 35 } 36 int main() 37 { 38 scanf("%d",&n); 39 for (int i=1,x;i<=n;i++) 40 { 41 scanf("%d",&x); 42 while (x) insert(x,i),scanf("%d",&x),d[i]++; 43 } 44 for (int i=1;i<=n;i++) if (!d[i]) insert(n+1,i),d[i]++; 45 topusort(); 46 for (int i=1;i<=n+1;i++) 47 { 48 int x=a[i],y=0; 49 for (int j=last[x];j;j=e[j].from) if (!y) y=e[j].to; else y=getlca(e[j].to,y); 50 fa[x][0]=y,deep[x]=deep[y]+1; 51 for (int j=1;j<=16;j++) fa[x][j]=fa[fa[x][j-1]][j-1]; 52 } 53 for (int i=n+1;i>=1;i--) size[a[i]]++,size[fa[a[i]][0]]+=size[a[i]]; 54 for (int i=1;i<=n;i++) printf("%d\n",size[i]-1); 55 }