[ZJOI 2012]灾难

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。保证输入的食物网没有环。

题解

拓扑排序+倍增LCA

暴力的n2算法肯定是不行的,我们需要考虑特殊的做法。

由于每次有且只有一种生物灭绝,而当且仅当x的所有食物都灭绝,x才会灭绝。

所以所有x的食物从上至下能共同达到的某个节点灭绝时,x才会灭绝。

根据这个我们可以重构树然后跑LCA。

先把所有没有食物的点(题目中描述为“生产者”)向0连一条边。

然后对原图进行拓扑排序,得到每个点进队列的顺序。

再从后向前扫一遍,对于每个点,对它的所有食物节点求一下LCA(两两求一次),将这个点连到LCA上。

由于我们加了“生产者”->0的一条边,所以能够使得加进来的是一棵树,而不是一个森林。

每次重构时,不需要LCT,直接看作新加一个节点x,f[x][0]=LCA,然后处理一下就行了。

最后要求的就是子树大小-1,所以利用拓扑排序(也就是一种bfs序)向上更新即可。

举样例的例子:

我们容易发现草的灾难值为4,羊的灾难值为1。

Ps:听说这东西叫灭绝树,还以为是什么奇怪的数据结构,就是拓扑排序+倍增LCA。估计这就是母题了吧?

神犇的注解:

    我们需要构造一棵“灭绝树”。
    “灭绝树”满足以下性质:对于一棵多叉树的任意一个结点,当它“灭绝”时,它所有的后代也会跟着“灭绝”。
    再回过来看这道题,题目要求的是某种生物“灭绝”后跟着“灭绝”的其他生物的数量,即这种生物在“灭绝树”中的后代数量。
    那么问题来了,怎么建立“灭绝树”?
    很显然,一种生物会“灭绝”只有两种情况:一是它原本就“灭绝”(即我们要求灾难值的那种生物),二是它所有的食物都“灭绝”。
    第一种情况不用考虑,那么我们来考虑第二种情况。
    假设有生物I。很显然,只有当生物I的所有食物的最近公共祖先(LCA)J“灭绝”时,生物I的所有食物才会同时“灭绝”(显然这里就要用到倍增求LCA的算法),然后,我们将生物I作为生物J的一个新的孩子节点,表示当J“灭绝”时,I也会跟着“灭绝”(因为它所有的食物都“灭绝”了)。
    根据题目需求,最后只要输出每种生物在“灭绝树”中的所有后代数量(数量的计算可以在每次“灭绝树”加入新节点时进行一次DFS)就可以了。
 1 #include<map>
 2 #include<ctime>
 3 #include<cmath>
 4 #include<queue>
 5 #include<stack>
 6 #include<cstdio>
 7 #include<string>
 8 #include<vector>
 9 #include<cstring>
10 #include<cstdlib>
11 #include<iostream>
12 #include<algorithm>
13 #define LL long long
14 #define RE register
15 #define IL inline
16 using namespace std;
17 const int N=65534;
18 const int M=1000000;
19
20 int n,x,op;
21 struct tt
22 {
23     int to,next;
24 }edge[M+5];
25 int path[N+5],top;
26 IL void Add(int u,int v);
27
28 int in[N+5];
29 int size[N+5];
30
31 int q[N+5],head,tail;
32 IL void Topsort();
33
34 int deep[N+5],fa[N+5][20];
35 IL int LCA(int x,int y);
36
37 int main()
38 {
39     scanf("%d",&n);
40     op=log2(n);
41     for (RE int i=1;i<=n;i++)
42     {
43         scanf("%d",&x);
44         if (!x) Add(i,0);
45         while (x)
46         {
47             Add(i,x);
48             in[x]++;
49             scanf("%d",&x);
50         }
51     }
52     Topsort();
53     for (RE int i=n;i>=1;i--)
54     {
55         int u=q[i],t=edge[path[u]].to;
56         for (RE int j=edge[path[u]].next;j;j=edge[j].next) t=LCA(t,edge[j].to);
57         fa[u][0]=t;
58         deep[u]=deep[t]+1;
59         for (RE int t=1;t<=op;t++) fa[u][t]=fa[fa[u][t-1]][t-1];
60     }
61     for (RE int i=1;i<=n;i++) size[q[i]]++,size[fa[q[i]][0]]+=size[q[i]];
62     for (RE int i=1;i<=n;i++) printf("%d\n",size[i]-1);
63     return 0;
64 }
65
66 IL void Topsort()
67 {
68     head=tail=1;
69     for (RE int i=1;i<=n;i++) if (!in[i]) q[tail++]=i;
70     while (head<tail)
71     {
72         int u=q[head++];
73         for (RE int i=path[u];i;i=edge[i].next)
74         {
75             in[edge[i].to]--;
76             if (!in[edge[i].to]) q[tail++]=edge[i].to;
77         }
78     }
79 }
80 IL void Add(int u,int v)
81 {
82     edge[++top].to=v;
83     edge[top].next=path[u];
84     path[u]=top;
85 }
86 IL int LCA(int x,int y)
87 {
88     if (deep[x]<deep[y]) swap(x,y);
89     for (RE int i=op;i>=0;i--) if (deep[fa[x][i]]>=deep[y]) x=fa[x][i];
90     if (x==y) return x;
91     for (RE int i=op;i>=0;i--) if (fa[x][i]!=fa[y][i]) x=fa[x][i],y=fa[y][i];
92     return fa[x][0];
93 }
时间: 2024-10-09 12:11:43

[ZJOI 2012]灾难的相关文章

BZOJ 2815 ZJOI 2012 灾难 动态倍增LCA

题目背景 阿米巴是小强的好朋友. 题目大意 给出一个食物链(拓扑图),定义一个生物所有的食物都灭绝了之后他自己也灭绝了.定义每种生物灭绝之后跟随着它灭绝的生物个数为这个生物的灾难值.求所有生物的灾难值. 思路 看题帽知出题人系列. fhq的题大家也知道,一般都是不可做的.于是我就去看了他的题解,发现这个题还是可做的. 定义一种灭绝树,对于任意一个子树,若这个子树的根节点灭绝,那么子树中的所有点都会灭绝.只要弄出这个树,我们就可以解决问题了. 先加一个超级食物,然后从这个点开始拓扑排序,保证处理到

数学 ZJOI 2012 数列

1 #include <iostream> 2 #include <cstring> 3 #include <cstdio> 4 using namespace std; 5 const int maxn=110; 6 struct ExtInt{ 7 int a[maxn],len; 8 ExtInt(){ 9 memset(a,0,sizeof(a)); 10 len=1; 11 } 12 void clear(){ 13 memset(a,0,sizeof(a))

BZOJ 2657 ZJOI 2012 旅游(journey) 树的直径

题目大意:给出一个凸多边形的三角剖分图,每一个三角形代表一个城市,现在连接这个图中的两个点,问最多能够经过多少个城市. 思路:浙江都是一帮神么.. 这题给的条件简直是不知所云啊..转化十分巧妙.因为每个凸n边形经过三角剖分之后会出现n - 2个三角形,任意一条边只会成为两个城市的公共边或者整个多边形的边.不难推出两个城市的公共边是n - 3条,也就是说把公共边看成是新图的边的话,就会新图就会构成一颗树.之后就是很水的树的直径了... CODE: #include <map> #include

BZOJ 2656 ZJOI 2012 数列(sequence) 高精度+记忆化搜索

题目大意:定义个一序列,f[i] = f[i / 2] (i % 2 == 0);f[i] = f[i / 2] + f[i / 2 + 1] (i % 2 == 1);求这个数列的第m项(m <= 10 ^ 100) 思路:数据范围高精度没跑了.记得之前做过这个题的弱化版,似乎是没有高精度的记忆化搜索,这个题就是加个高精度. CODE: #include <map> #include <cstdio> #include <cstring> #include &l

[ZJOI 2012] 网络

[题目链接] https://www.lydsy.com/JudgeOnline/problem.php?id=2816 [算法] 对每种颜色的边建一棵LCT , 维护联通性即可 时间复杂度 : O(C * NlogN ^ 2) [代码] #include<bits/stdc++.h> using namespace std; const int MAXN = 2e5 + 10; const int MAXC = 15; typedef long long ll; typedef long d

[ZJOI 2012]数列

Description 题库链接 给你一个数列 \(A\),满足递推公式 \[ A_n\left\{\begin{aligned}&0,&n=0\\&1,&n=1\\&A_\frac{n}{2},&2\mid n\\&A_{\left\lfloor\frac{n}{2}\right\rfloor}+A_{\left\lceil\frac{n}{2}\right\rceil},&\text{else}\end{aligned}\right. \

动态规划小练

终于意识到动规的水平差得一批了.这边开个小专题练一下. 题目列表是学长 frank_c1 的博客.这样一来可以保证质量,二来也有自己能看懂的题解. 事实上很多题意也是贺的 这里还是挂个链接吧:orz (刷新以获取数学公式) [APIO 2014] Beads and wires 题意 在达芬奇时代,有一个流行的儿童游戏称为连珠线.当然,这个游戏是关于珠子和线的.线是红色或蓝色的,珠子被编号为 $ 1 $ 到 $ n $ .这个游戏从一个珠子开始,每次会用如下方式添加一个新的珠子: $ Appen

SQL Server 2012笔记分享-22:理解备份模式与恢复模式

SQL Server 备份和还原组件为保护存储在 SQL Server 数据库中的关键数据提供了基本安全保障. 为了最大限度地降低灾难性数据丢失的风险,您需要定期备份数据库以保留对数据所做的修改. 规划良好的备份和还原策略有助于防止SQL Server 2012笔记分享-22:理解备份模式与恢复模式数据库因各种故障而造成数据丢失. 通过还原一组备份,然后恢复数据库来测试您的策略,以便为有效地应对灾难做好准备. ===========================================

摩根大通银行被黑客攻克, ATM机/网银危在旦夕,winxp退市灾难来临了

winxp4月退市到如今还不到半年,就出现故障了 7600多万个消费者银行账户被黑.此外还有700万个小企业账户的信息也被黑客窃取,这个算不算灾难呢?假设等到银行业彻底崩溃,资金彻底丧失,那不仅仅是灾难,而是末日. 因为越来越多黑客受雇于组织.针对winxp退市的唾手可得的攻击成了他们的巨大狂欢.我觉得黑客可能利用winxp漏洞入侵atm机后再进入银行网络.在没有安全操作系统(windows不安全众人皆知)情况下把数据放到云服务.等于把安全钥匙交给了黑客.摩根发布这些事件是想获得针对账户攻击的免