题目描述(转自洛谷)

阿米巴是小强的好朋友。

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

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

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

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

这个图没有环。

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

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

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

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

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

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

输入

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

接下来 N 行,每行描述了一个生物可以吃的其他生物的列表,格式为用空格隔开的若干个数字,每个数字表示一种生物的标号,最后一个数字是 0 表示列表的结束。

输出

包含N行,每行一个整数,表示每个生物的灾难值。

样例输入

5
0
1 0
1 0
2 3 0
2 0

样例输出

4
1
0
0
0


题解

拓扑排序+倍增LCA

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

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

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

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

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

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

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

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

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

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

#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
int n , head[70000] , to[1000000] , next[1000000] , cnt , rd[70000] , q[70000] , l = 1 , r , fa[70000][20] , deep[70000] , log[70000] , si[70000];
void add(int x , int y)
{
to[++cnt] = y;
next[cnt] = head[x];
head[x] = cnt;
}
void topsort()
{
int i , j , x;
for(i = 0 ; i <= n ; i ++ ) for(j = head[i] ; j ; j = next[j]) rd[to[j]] ++ ;
for(i = 0 ; i <= n ; i ++ ) if(!rd[i]) q[++r] = i;
while(l <= r)
{
x = q[l ++ ];
for(i = head[x] ; i ; i = next[i])
{
rd[to[i]] -- ;
if(!rd[to[i]]) q[++r] = to[i];
}
}
}
int lca(int x , int y)
{
int i;
if(deep[x] < deep[y]) swap(x , y);
for(i = log[deep[x] - deep[y]] ; ~i ; i -- )
if(deep[x] - (1 << i) >= deep[y])
x = fa[x][i];
if(x == y) return x;
for(i = log[deep[x]] ; ~i ; 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 , t , x;
scanf("%d" , &n);
for(i = 1 ; i <= n ; i ++ )
{
scanf("%d" , &t);
if(!t) add(i , 0);
else
{
do
{
add(i , t);
scanf("%d" , &t);
}while(t);
}
}
topsort();
for(i = 2 ; i <= n + 1 ; i ++ ) log[i] = log[i >> 1] + 1;
for(i = n ; i ; i -- )
{
x = q[i] , t = to[head[x]];
for(j = next[head[x]] ; j ; j = next[j]) t = lca(t , to[j]);
fa[x][0] = t;
deep[x] = deep[t] + 1;
for(j = 1 ; j <= log[deep[x]] ; j ++ ) fa[x][j] = fa[fa[x][j - 1]][j - 1];
}
for(i = 1 ; i <= n ; i ++ ) si[q[i]] ++ , si[fa[q[i]][0]] += si[q[i]];
for(i = 1 ; i <= n ; i ++ ) printf("%d\n" , si[i] - 1);
return 0;
}

【bzoj2815】[ZJOI2012]灾难 拓扑排序+倍增LCA的更多相关文章

  1. BZOJ 2815: [ZJOI2012]灾难 拓扑排序+倍增LCA

    这种问题的转化方式挺巧妙的. Code: #include <bits/stdc++.h> #define N 100000 #define M 1000000 #define setIO ...

  2. BZOJ2815:[ZJOI2012]灾难(拓扑排序,LCA)

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

  3. 洛谷P2597 [ZJOI2012] 灾难 [拓扑排序,LCA]

    题目传送门 灾难 题目描述 阿米巴是小强的好朋友. 阿米巴和小强在草原上捉蚂蚱.小强突然想,如果蚂蚱被他们捉灭绝了,那么吃蚂蚱的小鸟就会饿死,而捕食小鸟的猛禽也会跟着灭绝,从而引发一系列的生态灾难. ...

  4. [BZOJ2815][ZJOI2012]灾难(拓扑排序/支配树)

    支配树目前只见到这一个应用,那就不独分一类,直接作为拓扑排序题好了. 每个点向所有食物连边,定义fa[x]为x的支配点,即离x最近的点,满足若fa[x]灭绝,则x也要灭绝. 这样,将fa[x]向x连边 ...

  5. 【BZOJ2815】[ZJOI2012]灾难 拓扑排序+LCA

    [BZOJ2815][ZJOI2012]灾难 题目描述 阿米巴是小强的好朋友. 阿米巴和小强在草原上捉蚂蚱.小强突然想,果蚂蚱被他们捉灭绝了,那么吃蚂蚱的小鸟就会饿死,而捕食小鸟的猛禽也会跟着灭绝,从 ...

  6. P2597 [ZJOI2012]灾难——拓扑,倍增,LCA

    最近想学支配树,但是基础还是要打好了的: P2597 [ZJOI2012]灾难 这道题是根据食物链链接出一个有向图的关系,求一个物种的灭绝会连带几种物种的灭绝: 求得就是一个点能支配几个点: 如果一个 ...

  7. P2597 [ZJOI2012]灾难 拓扑排序

    这个题有点意思,正常写法肯定会T,然后需要优化.先用拓扑排序重构一遍树,然后进行一个非常神奇的操作:把每个点放在他的食物的lca上,然后计算的时候直接dfs全加上就行了.为什么呢,因为假如你的食物的l ...

  8. [BZOJ2815][ZJOI2012]灾难 灭绝树+拓扑排序+lca

    灾难 [问题描述] 阿米巴是小强的好朋友. 阿米巴和小强在草原上捉蚂蚱.小强突然想,如果蚂蚱被他们捉灭绝了,那 么吃蚂蚱的小鸟就会饿死,而捕食小鸟的猛禽也会跟着灭绝,从而引发一系列的 生态灾难. 学过 ...

  9. 【bzoj2815】灾难[ZJOI2012](拓扑排序+lca)

    题目传送门:http://www.lydsy.com/JudgeOnline/problem.php?id=2815 原版题解:http://fanhq666.blog.163.com/blog/st ...

随机推荐

  1. struts2入门第一天----------一个简单例

    搭建完环境后就可以动手去打代码了.首先创建一个简单的提交表单的jsp页面(html页面也可以), <%@ page language="java" import=" ...

  2. python字符串,数组操作

    今天倒是学到了很多知识,了解了python的基本数组,以及可变类型和不可变类型,还有元组,列表,字典等等的用法 然后作业如下 其中在做往list列表加东西时候遇到了小毛病,用户从控制台输入的是一个字符 ...

  3. C语言实现计算二进制数字1的个数

    #include<stdio.h> #include<stdlib.h> int print_one_bits01(unsigned int value){ //0000 11 ...

  4. 005---基于UDP的套接字

    基于UDP的套接字 udp不同于tcp协议:不需要经过三次握手.四次挥手.直接发送数据就行. 服务端 import socket ip_port = ('127.0.0.1', 8001) buffe ...

  5. 005---Python数据类型--字典

    字典 .caret, .dropup > .btn > .caret { border-top-color: #000 !important; } .label { border: 1px ...

  6. Python tips(

    (此文是在实际工程中遇到的一些小问题,给予解决和整理.解决方法大多来自网上零散的文章.有一个系统化的Python问题解决方案,来自<Python 3 学习笔记>雨痕著,其中对Python的 ...

  7. WCF入门四[WCF的通信模式]

    一.概述 WCF的通信模式有三种:请求/响应模式.单向模式和双工通信. 二.请求/响应模式 请求/响应模式就是WCF的默认模式,前面几篇随笔中的示例都是这种模式,当客户端发送请求后(非异步状态下),即 ...

  8. ReentrantLock类的hasQueuedPredecessors方法和head节点的含义

    部分启发来源自文章:Java并发编程--Lock PART 1 1.如果h==t成立,h和t均为null或是同一个具体的节点,无后继节点,返回false.2.如果h!=t成立,head.next是否为 ...

  9. XenServer设置master,摧毁故障主机

    XenServer pool 移除server 设置master 这分为Pool Master是正常还是异常2种情况: 正常情况下可能要对Pool Master做一些停机维护,比如换内存条啥的,此时在 ...

  10. Promise关键知识

    异步是ES6中使用频率最高的特性之一,也是面试中经常会被问到的问题,特此整理了相应的笔记 一.Promise的三种状态 pending-异步操作没有结束 fulfilled-异步操作已成功结束,最常见 ...