bzoj2815 [ZJOI2012]灾难

(bzoj没有题面,题面复制自洛谷)

题目描述

阿米巴是小强的好朋友。

阿米巴和小强在草原上捉蚂蚱。小强突然想,果蚂蚱被他们捉灭绝了,那么吃蚂蚱的小鸟就会饿死,而捕食小鸟的猛禽也会跟着灭绝,从而引发一系列的生态灾难。

学过生物的阿米巴告诉小强,草原是一个极其稳定的生态系统。如果蚂蚱灭绝了,小鸟照样可以吃别的虫子,所以一个物种的灭绝并不一定会引发重大的灾难。

我们现在从专业一点的角度来看这个问题。我们用一种叫做食物网的有向图来描述生物之间的关系:

一个食物网有N个点,代表N种生物,如果生物x可以吃生物y,那么从y向x连一个有向边。

这个图没有环。

图中有一些点没有连出边,这些点代表的生物都是生产者,可以通过光合作用来生存; 而有连出边的点代表的都是消费者,它们必须通过吃其他生物来生存。

如果某个消费者的所有食物都灭绝了,它会跟着灭绝。

我们定义一个生物在食物网中的“灾难值”为,如果它突然灭绝,那么会跟着一起灭绝的生物的种数。

举个例子:在一个草场上,生物之间的关系是:

如果小强和阿米巴把草原上所有的羊都给吓死了,那么狼会因为没有食物而灭绝,而小强和阿米巴可以通过吃牛、牛可以通过吃草来生存下去。所以,羊的灾难值是1。但是,如果草突然灭绝,那么整个草原上的5种生物都无法幸免,所以,草的灾难值是4。

给定一个食物网,你要求出每个生物的灾难值。

 

输入输出格式

输入格式:

输入文件 catas.in 的第一行是一个正整数 N,表示生物的种数。生物从 1 标

号到 N。

接下来 N 行,每行描述了一个生物可以吃的其他生物的列表,格式为用空

格隔开的若干个数字,每个数字表示一种生物的标号,最后一个数字是 0 表示列

表的结束。

 

输出格式:

输出文件catas.out包含N行,每行一个整数,表示每个生物的灾难值。

 

输入输出样例

输入样例#1:
5
0
1 0
1 0
2 3 0
2 0
输出样例#1:
4
1
0
0
0

说明

【样例说明】

样例输入描述了题目描述中举的例子。

【数据规模】

对50%的数据,N ≤ 10000。

对100%的数据,1 ≤ N ≤ 65534。

输入文件的大小不超过1M。保证输入的食物网没有环。

 

 

复制老师给的题解:

      首先知道一个点至多有一个点使得那个点删除后直接影响到该点的,所以可以想到树形结构,也就是建立一棵“灭绝树”,“灭绝树”满足以下性质:对于一棵多叉树的任意一个结点,当它“灭绝”时,它所有的后代也会跟着“灭绝”。如何建立呢?首先利用拓扑序顺序进行操作,因为在前面的点可以影响到后面的点,而做到后面的点的时候前面的点已经处理完毕了,然后利用图的反向图,该点在灭绝树中的父亲是在反向图中所有儿子的LCA,因为只有LCA灭绝了才可以导致该点直接灭绝,那么最后答案显然就是一个点在灭绝树中的子树大小,由于可能有多个根节点,所以我们假设一个超级点为0,如果一个点入度为0则连向0,由0跑DFS求size(子树个数),最后size要-1。

 

刚开始不知道lca怎么搞,上网看了一下以为要lct有点怕,后来发现虽然树在变,但还是可以倍增乱搞。

 1 program catas(input,output);
 2 type
 3   etype=record
 4      t,next:longint;
 5   end;
 6 var
 7   e:array[0..10000000]of etype;
 8   a,rea,r,d,q,ans:array[0..100010]of longint;
 9   f:array[0..100010,0..18]of longint;
10   n,i,j,k,x,cnt,h,t:longint;
11 procedure add1(x,y:longint);
12 begin
13    inc(cnt);e[cnt].t:=y;e[cnt].next:=a[x];a[x]:=cnt;
14 end;
15 procedure add2(x,y:longint);
16 begin
17    inc(cnt);e[cnt].t:=y;e[cnt].next:=rea[x];rea[x]:=cnt;
18 end;
19 function lca(x,y:longint):longint;
20 begin
21    if d[x]<d[y] then begin k:=x;x:=y;y:=k; end;
22    for k:=16 downto 0 do if d[f[x,k]]>=d[y] then x:=f[x,k];
23    if x=y then exit(x);
24    for k:=16 downto 0 do if f[x,k]<>f[y,k] then begin x:=f[x,k];y:=f[y,k]; end;
25    exit(f[x,0]);
26 end;
27 begin
28    assign(input,'catas.in');assign(output,'catas.out');reset(input);rewrite(output);
29    readln(n);
30    fillchar(r,sizeof(r),0);
31    fillchar(a,sizeof(a),0);fillchar(rea,sizeof(rea),0);cnt:=0;
32    for i:=1 to n do begin read(x);while x<>0 do begin add1(x,i);add2(i,x);inc(r[i]);read(x); end; end;
33    h:=0;t:=0;d[0]:=0;
34    for i:=1 to n do if r[i]=0 then begin inc(t);q[t]:=i;d[i]:=1;for j:=0 to 16 do f[i,j]:=0; end;
35    while h<t do
36       begin
37          inc(h);i:=a[q[h]];
38          while i<>0 do
39             begin
40                dec(r[e[i].t]);
41                if r[e[i].t]=0 then
42                   begin
43                      inc(t);q[t]:=e[i].t;
44                      j:=rea[e[i].t];x:=e[j].t;j:=e[j].next;
45                      while j<>0 do begin x:=lca(x,e[j].t);j:=e[j].next; end;
46                      f[e[i].t,0]:=x;d[e[i].t]:=d[x]+1;x:=e[i].t;
47                      for j:=1 to 16 do f[x,j]:=f[f[x,j-1],j-1];
48                   end;
49                i:=e[i].next;
50             end;
51       end;
52    for i:=1 to n do ans[i]:=1;
53    for i:=n downto 1 do inc(ans[f[q[i],0]],ans[q[i]]);
54    for i:=1 to n do writeln(ans[i]-1);
55    close(input);close(output);
56 end.

 

posted @ 2017-04-02 18:53  Klaier  阅读(183)  评论(0编辑  收藏  举报