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被破坏就可以,所以我们 ...
随机推荐
- QYH练字
汉字书写笔划,提取自百度汉语等网站... 以下凑字数: [发文说明]博客园是面向开发者的知识分享社区,不允许发布任何推广.广告.政治方面的内容.博客园首页(即网站首页)只能发布原创的.高质量的.能让读 ...
- Access to XMLHttpRequest at 'XXX' from origin 'XX' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present o AJAX跨域请求解决方法
今天出现了一个问题找了好久先看代码: 这可能是个BUG吧插入代码: dataType: 'jsonp', crossDomain: true, 最终:
- ScheduledExecutorService的两种方法
开发中,往往遇到另起线程执行其他代码的情况,用java定时任务接口ScheduledExecutorService来实现. ScheduledExecutorService是基于线程池设计的定时任务类 ...
- 简单测试--C#实现中文汉字转拼音首字母
第一种: 这个是自己写的比较简单的实现方法,要做汉字转拼音首字母,首先应该有一个存储首字母的数组,然后将要转拼音码的汉字与每个首字母开头的第一个汉字即“最小”的汉字作比较,这里的最小指的是按拼音规则比 ...
- 悟空模式-java-原型模式
[却说那妖精与大圣斗经半日,不分胜败.行者把棒丢起,叫一声“变!”就以一变十,以十变百,以百变千,半天里,好似蛇游蟒搅,乱打妖邪.妖邪慌了手脚,将身一闪,化道清风,即奔碧空之上逃走.行者念声咒语,将铁 ...
- HDU2732(KB11-K 最大流)
Leapin' Lizards Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)T ...
- POJ1222(SummerTrainingDay01-E)
EXTENDED LIGHTS OUT Time Limit: 1000MS Memory Limit: 10000K Total Submissions: 11078 Accepted: 7 ...
- (三)MongoDB数据库注意
1.数据库名 数据库也通过名字来标识.数据库名可以是满足以下条件的任意UTF-8字符串. 不能是空字符串(""). 不得含有' '(空格)...$./.\和\0 (空字符). 应全 ...
- JavaScript 数组复制的方法
1.循环 2.Array.from(arr) 3.let arr2 = [...arr]
- [原创.数据可视化系列之八]使用等d3进行灰度图转伪彩色
对灰度图进行彩色化是数据可视化中常见的需求,使用d3在客户端比较容易实现,本文使用d3生成图片,并显示: 代码如下: 代码中首先下载数据文件,然后设定d3的色带信息,生成一个空白的canvas元素,并 ...