题目描述
阿米巴是小强的好朋友。
阿米巴和小强在草原上捉蚂蚱。小强突然想,如果蚂蚱被他们捉灭绝了,那么吃蚂蚱的小鸟就会饿死,而捕食小鸟的猛禽也会跟着灭绝,从而引发一系列的生态灾难。
学过生物的阿米巴告诉小强,草原是一个极其稳定的生态系统。如果蚂蚱灭绝了,小鸟照样可以吃别的虫子,所以一个物种的灭绝并不一定会引发重大的灾难。
我们现在从专业一点的角度来看这个问题。我们用一种叫做食物网的有向图来描述生物之间的关系:
一个食物网有N个点,代表N种生物,如果生物x可以吃生物y,那么从y向x连一个有向边。
这个图没有环。
图中有一些点没有连出边,这些点代表的生物都是生产者,可以通过光合作用来生存; 而有连出边的点代表的都是消费者,它们必须通过吃其他生物来生存。
如果某个消费者的所有食物都灭绝了,它会跟着灭绝。
我们定义一个生物在食物网中的“灾难值”为,如果它突然灭绝,那么会跟着一起灭绝的生物的种数。
举个例子:在一个草场上,生物之间的关系是:
如
如果小强和阿米巴把草原上所有的羊都给吓死了,那么狼会因为没有食物而灭绝,而小强和阿米巴可以通过吃牛、牛可以通过吃草来生存下去。所以,羊的灾难值是1。但是,如果草突然灭绝,那么整个草原上的5种生物都无法幸免,所以,草的灾难值是4。
给定一个食物网,你要求出每个生物的灾难值。
输入格式
输入文件 catas.in 的第一行是一个正整数 N,表示生物的种数。生物从 1 标
号到 N。
接下来 N 行,每行描述了一个生物可以吃的其他生物的列表,格式为用空
格隔开的若干个数字,每个数字表示一种生物的标号,最后一个数字是 0 表示列
表的结束。
输出格式
输出文件catas.out包含N行,每行一个整数,表示每个生物的灾难值。
输入输出样例
输入
5
0
1 0
1 0
2 3 0
2 0
输出
4
1
0
0
0
说明/提示
【样例说明】
样例输入描述了题目描述中举的例子。
【数据规模】
对50%的数据,N ≤ 10000。
对100%的数据,1 ≤ N ≤ 65534。
输入文件的大小不超过1M。保证输入的食物网没有环。
题解
这题我搞了差不多两三天吧,我先是去搞了一下支配树(显而易见没有搞懂)
然后我发现这题不用搞支配树呀。。
运用支配树的思想,并拓扑排序,这样的话当你把拓扑排序后的前 x − 1 x-1 x−1个点加入支配树后,指向第 x x x个点的所有点就都在支配树里了,那么新加进来的这个点就应该被加到所有指向他的点的 l c a lca lca的儿子中,因为只有当所有指向他的点都灭绝了他才会灭绝,而能够使他直接灭绝的点就是所有指向他的点的 l c a lca lca。
然后搞出支配树之后,能够支配这个点的点集就是它的祖先,被这个点支配的点集就是它的子树。
代码并不难理解,也很好打:
PS:
支配树,顾名思义,就是棵树,树上每个节点的父亲就是他的最近支配点(离他最近的支配点)
# include <algorithm>
# include <cstring>
# include <cmath>
# include <climits>
# include <iostream>
# include <string>
# include <set>
# include <map>
# include <queue>
# include <stack>
# include <cctype>
# include <cstdlib>
using namespace std;
namespace fastio{
template<typename tn> void read(tn &a){
tn x=0,f=1;char c=' ';
for(;!isdigit(c);c=getchar()) if(c=='-') f=-1;
for(;isdigit(c);c=getchar() ) x=x*10+c-'0';
a=x*f;
}
template<typename tn> void print(tn a){
if(a<0) putchar('-'),a=-a;
if(a>9) print(a/10);
putchar(a%10+'0');
}
};
using namespace fastio;
const int N=7e4+5;
vector<int> son[N],fa[N];
int f[N][20],d[N],lg[N];
struct Edge{
int nex,to;
}e[N];
int rd[N],head[N],cnt;
void add(int x,int y){
e[++cnt].nex=head[x];
e[cnt].to=y;
head[x]=cnt;
}
int n;
queue<int> q;
void update(int x,int fa){
d[x]=d[fa]+1;
f[x][0]=fa;
for(int i=1;i<20;i++) f[x][i]=f[f[x][i-1]][i-1];
return;
}
int lca(int x,int y){
if(d[x]<d[y]) swap(x,y);
while(d[x]>d[y]) x=f[x][lg[d[x]-d[y]]-1];
if(x==y) return x;
for(int k=lg[d[x]]-1;k>=0;k--)
if(f[x][k]!=f[y][k])
x=f[x][k],y=f[y][k];
return f[x][0];
}
int siz[N];
void dfs(int x){
siz[x]=1;
for(int i=head[x];i;i=e[i].nex)
dfs(e[i].to),siz[x]+=siz[e[i].to];
}
int main(){
read(n);
for(int i=1;i<=n;i++)
lg[i]=lg[i-1]+(1<<lg[i-1]==i);
for(int i=1;i<=n;i++){
int x;
while("xyclovesqyn"){
read(x);
if(x==0) break;
son[x].push_back(i);
fa[i].push_back(x); //lippahha depil
rd[i]++;
}
}
for(int i=1;i<=n;i++)
if(rd[i]==0) q.push(i),add(0,i),d[i]=1;
while(q.size()){
int x=q.front();
q.pop();
int xyc=son[x].size();
for(int i=0;i<xyc;i++){
int y=son[x][i];
rd[y]--;
if(!rd[y]){
int qyn=fa[y].size();
int lav=fa[y][0];
for(int j=1;j<qyn;j++) lav=lca(lav,fa[y][j]);
add(lav,y);
update(y,lav);
q.push(y);
}
}
}
dfs(0);
for(int i=1;i<=n;i++) print(siz[i]-1),puts("");
return 0;
}