BZOJ2815:[ZJOI2012]灾难(拓扑排序,LCA)
Description
阿米巴是小强的好朋友。
阿米巴和小强在草原上捉蚂蚱。小强突然想,如果蚂蚱被他们捉灭绝了,那么吃蚂蚱的小鸟就会饿死,而捕食小鸟的猛禽也会跟着灭绝,从而引发一系列的生态灾难。
学过生物的阿米巴告诉小强,草原是一个极其稳定的生态系统。如果蚂蚱灭绝了,小鸟照样可以吃别的虫子,所以一个物种的灭绝并不一定会引发重大的灾难。
我们现在从专业一点的角度来看这个问题。我们用一种叫做食物网的有向图来描述生物之间的关系:
一个食物网有N个点,代表N种生物,如果生物x可以吃生物y,那么从y向x连一个有向边。
这个图没有环。
图中有一些点没有连出边,这些点代表的生物都是生产者,可以通过光合作用来生存; 而有连出边的点代表的都是消费者,它们必须通过吃其他生物来生存。
如果某个消费者的所有食物都灭绝了,它会跟着灭绝。
我们定义一个生物在食物网中的“灾难值”为,如果它突然灭绝,那么会跟着一起灭绝的生物的种数。
举个例子:在一个草场上,生物之间的关系是:
如 
如果小强和阿米巴把草原上所有的羊都给吓死了,那么狼会因为没有食物而灭绝,而小强和阿米巴可以通过吃牛、牛可以通过吃草来生存下去。所以,羊的灾难值是1。但是,如果草突然灭绝,那么整个草原上的5种生物都无法幸免,所以,草的灾难值是4。
给定一个食物网,你要求出每个生物的灾难值。
Input
输入文件 catas.in 的第一行是一个正整数 N,表示生物的种数。生物从 1 标
号到 N。
接下来 N 行,每行描述了一个生物可以吃的其他生物的列表,格式为用空
格隔开的若干个数字,每个数字表示一种生物的标号,最后一个数字是 0 表示列
表的结束。
Output
输出文件catas.out包含N行,每行一个整数,表示每个生物的灾难值。
Sample Input
1 2 3
1 4 5
2 4 7
2 3 6
3 4 8
Sample Output
3 6
Solution
感谢zhhe0101学长orz的耐心讲解
我太菜了听了好久才懂
不过这个题的做法的确是十分精妙的
大体分三步:1、拓扑排序2、建树3、求树的前缀和
1、我们知道,一个生物死亡的条件是他的所有食物全部死亡
而且既然这个题说了没有环,那么就可以保证食物链等级鲜明
那么求这种图,我们很容易就可以想到拓扑排序了
2、我们建一棵树,让father[x]为x的父亲,意味着若father[x]死了,那么x则灭绝
问题来了,x应该挂在哪个点上?
当然是他所有食物的LCA上啊!
若LCA死了,x的食物也会都死亡,那么x也必然死亡
建树这里可以将出度为0的点连在一个虚拟点n+1上方便处理
3、最后DFS求一下树的前缀和
因为若x死了,那么他的子树会全部死亡,那么他的重要度就是子树大小-1(去除本身)
最后附样例转树的图(学长给我画的)
5 →2 →1
↗ ↗
4 →3
6
↓
1
↙↓↘
2 3 4
↙
5
Code
#include<iostream>
#include<cstdio>
#include<queue>
#define MAXN (65534+5)
using namespace std;
int head1[MAXN],head[MAXN],num1,num2;
int n,ind[MAXN],sum,topo[MAXN];
int father[MAXN],f[MAXN][],depth[MAXN];
int SUM[MAXN]; //1为拓扑序所用邻接表
//2为树所用邻接表
struct node1
{
int to,next;
}edge1[MAXN*];//这里不是很懂为什么要开MAXN*4……?
void add1(int u,int v)
{
edge1[++num1].to=v;
edge1[num1].next=head1[u];
head1[u]=num1;
}
struct node
{
int to,next;
}edge[MAXN*+];
void add(int u,int v)
{
edge[++num2].to=v;
edge[num2].next=head[u];
head[u]=num2;
} //toposort拓扑排序
//RMQ倍增做LCA的预处理
//LCA找两个点的最近公共祖先
//build将拓扑排序转换为一颗有根树
//DPtree求树上前缀和
void toposort()
{
queue<int>q;
for (int i=;i<=n;++i)
if(ind[i]==)
q.push(i); while (!q.empty())
{
int x=q.front();
q.pop();
topo[++sum]=x;
for (int i=head1[x];i!=;i=edge1[i].next)
{
ind[edge1[i].to]--;
if(!ind[edge1[i].to])
q.push(edge1[i].to);
}
}
}
void RMQ(int x)
{
f[x][]=father[x];
for (int i=;i<=;++i)
f[x][i]=f[f[x][i-]][i-];
}
int LCA(int x,int y)//x is under y
{
if (depth[x]<depth[y]) swap(x,y);
for (int i=;i>=;--i)
if (f[x][i]!=&&depth[f[x][i]]>=depth[y])
x=f[x][i];
if (x==y) return y;
for (int i=;i>=;--i)
if (f[x][i]!=&&f[y][i]!=&&f[x][i]!=f[y][i])
{
x=f[x][i];
y=f[y][i];
}
return father[x];
}
void build()
{
depth[n+]=;
father[n+]=n+;
for (int i=n;i>=;--i)
{
int x=topo[i];
if (head1[x]==)
{
father[x]=n+;
add(n+,x);
f[x][]=n+;
depth[x]=;
continue;
}
int lca=edge1[head1[x]].to;
for (int i=edge1[head1[x]].next;i!=;i=edge1[i].next)
{
lca=LCA(lca,edge1[i].to);
}
father[x]=lca;
add(father[x],x);
depth[x]=depth[father[x]]+;
RMQ(x);
}
}
void DPtree(int x)
{
SUM[x]=;
for (int i=head[x];i!=;i=edge[i].next)
{
DPtree(edge[i].to);
SUM[x]+=SUM[edge[i].to];
}
} //main函数
int main()
{
int x;
scanf("%d",&n);
for (int i=;i<=n;++i)
{
scanf("%d",&x);
while (x!=)
{
add1(i,x);
++ind[x];//食物入度+1
scanf("%d",&x);
}
}
toposort();//拓扑排序
build();//建树
DPtree(n+);
for (int i=;i<=n;++i)
printf("%d\n",SUM[i]-);
}
BZOJ2815:[ZJOI2012]灾难(拓扑排序,LCA)的更多相关文章
- 【BZOJ2815】[ZJOI2012]灾难 拓扑排序+LCA
[BZOJ2815][ZJOI2012]灾难 题目描述 阿米巴是小强的好朋友. 阿米巴和小强在草原上捉蚂蚱.小强突然想,果蚂蚱被他们捉灭绝了,那么吃蚂蚱的小鸟就会饿死,而捕食小鸟的猛禽也会跟着灭绝,从 ...
- [BZOJ2815][ZJOI2012]灾难(拓扑排序/支配树)
支配树目前只见到这一个应用,那就不独分一类,直接作为拓扑排序题好了. 每个点向所有食物连边,定义fa[x]为x的支配点,即离x最近的点,满足若fa[x]灭绝,则x也要灭绝. 这样,将fa[x]向x连边 ...
- 【bzoj2815】[ZJOI2012]灾难 拓扑排序+倍增LCA
题目描述(转自洛谷) 阿米巴是小强的好朋友. 阿米巴和小强在草原上捉蚂蚱.小强突然想,果蚂蚱被他们捉灭绝了,那么吃蚂蚱的小鸟就会饿死,而捕食小鸟的猛禽也会跟着灭绝,从而引发一系列的生态灾难. 学过生物 ...
- 【bzoj2815】灾难[ZJOI2012](拓扑排序+lca)
题目传送门:http://www.lydsy.com/JudgeOnline/problem.php?id=2815 原版题解:http://fanhq666.blog.163.com/blog/st ...
- 洛谷P2597 [ZJOI2012] 灾难 [拓扑排序,LCA]
题目传送门 灾难 题目描述 阿米巴是小强的好朋友. 阿米巴和小强在草原上捉蚂蚱.小强突然想,如果蚂蚱被他们捉灭绝了,那么吃蚂蚱的小鸟就会饿死,而捕食小鸟的猛禽也会跟着灭绝,从而引发一系列的生态灾难. ...
- P2597 [ZJOI2012]灾难 拓扑排序
这个题有点意思,正常写法肯定会T,然后需要优化.先用拓扑排序重构一遍树,然后进行一个非常神奇的操作:把每个点放在他的食物的lca上,然后计算的时候直接dfs全加上就行了.为什么呢,因为假如你的食物的l ...
- BZOJ 2815: [ZJOI2012]灾难 拓扑排序+倍增LCA
这种问题的转化方式挺巧妙的. Code: #include <bits/stdc++.h> #define N 100000 #define M 1000000 #define setIO ...
- [BZOJ2815][ZJOI2012]灾难 灭绝树+拓扑排序+lca
灾难 [问题描述] 阿米巴是小强的好朋友. 阿米巴和小强在草原上捉蚂蚱.小强突然想,如果蚂蚱被他们捉灭绝了,那 么吃蚂蚱的小鸟就会饿死,而捕食小鸟的猛禽也会跟着灭绝,从而引发一系列的 生态灾难. 学过 ...
- 【题解】 [ZJOI2012]灾难 (拓扑排序+LCA)
懒得复制,戳我戳我 Solution: 这题思路很神奇,首先你要知道这个毁灭树是怎么保证实现的:一句话就是如果该节点要被破坏,他的所有父节点就要被破坏,也就只要所有父节点的LCA被破坏就可以,所以我们 ...
随机推荐
- Spring基础(5): 构造函数注入无法处理循环依赖
public class Person{ public Leader leader; public Person(Leader l){ this.leader= l; } } public class ...
- C#基础知识回顾:2.使用DbProviderFactory实现多数据库访问
ADO.Net 2.0中,在System.Data.Common中引入了一系列抽象基类,使得开发人员能够在不依赖具体数据库操作的情况下进行编写数据访问代码,它们分别是DbConnection.DbCo ...
- DataSet & DataTable &DataRow 深入浅出
本篇文章适合有一定的基础的人去查看 ,最好学习过一定net 编程基础在来查看此文章. 1.概念 DataSet是ADO.NET的中心概念.可以把DataSet当成内存中的数据库,DataSet是不依赖 ...
- EF只更新变化的字段
摘要 在使用EF的时候,由于表字段较多,所以在更新的时候,想要只更新变化的字段,有没有办法呢? 解决办法 代码片段 public async Task<int> UpdateAsync(T ...
- 3.C#知识点:is和as
IS和AS 都是用于类型转换的操作. 但是这两个有什么区别呢? 简单的来说 is 判断成立则返回True,反之返回false.as 成立则返回要转换的对象,不成立则返回Null. 下面掏一手代码来说明 ...
- Shiro遇到的SecurityManager红色警告
问题如图 需要添加一个导入 import org.apache.shiro.mgt.SecurityManager; 这样就不会报错了
- 在mysql中RIGHT JOIN与group by一起使用引起的一个大bug
本来按理说这个小问题不值得写一个博客的,不过正是这个小问题造成了一个大bug. 本来每月对数据都好好的,但是这一两天突然发现许多数据明显不对,这一块的代码和sql有些不是我写的,不过出现了bug,还是 ...
- Java基础知识你知道多少?
Java虚拟机基础知识你知道多少? Java并发基础知识你知道多少? Java数据结构基础知识你知道多少? java序列化与反序列化 https://github.com/zhantong/inter ...
- js 微信支付
引入 <script type="text/javascript" src="http://res.wx.qq.com/open/js/jweixin-1.2.0. ...
- CF712E Memory and Casinos
设\(f[i]\)为从\(i\)到\(r+1\)且不走出区间的概率 \(f[i]=p[i]f[i+1]+(1-p[i])f[i-1]\) \(f[i]-f[i-1]=p[i](f[i+1]-f[i-1 ...