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基础(7) : Bean的名字
1.普通bean是用id标志,context.getBean时传入名称即可获得. <bean id="p" class="com.Person"/> ...
- .NET 简单导出CSV文件
Response.ClearContent(); Response.AddHeader("content-disposition", "attachment; filen ...
- C# 最大二叉堆算法
C#练习二叉堆算法. namespace 算法 { /// <summary> /// 最大堆 /// </summary> /// <typeparam name=&q ...
- [日常] Go语言圣经-Goroutines和线程
Goroutines和线程: 1.动态栈: 1)线程都有一个固定大小的内存块(一般会是2MB)来做栈 2)一个goroutine会以一个很小的栈开始其生命周期,一般只需要2KB,不是固定的:栈的大小会 ...
- github小白上传本地代码及更新代码到GitHub及华为云教程
上传本地代码 第一步:去github上创建自己的Repository,创建页面如下图所示: 红框为新建的仓库的https地址 第二步: echo "# Test" >> ...
- ubuntu 18.04 设置固定ip
# This file is generated from information provided by # the datasource. Changes to it will not pers ...
- CSS3实现的几个小loading效果
昨晚上闲的没事突然想做几个小loading效果,下面是昨晚上做的几个小案例,分享给大家 1.水波loading:这个loading是我觉得非常简单,但是看上去的效果却非常不错的一个小loading 这 ...
- css 文本两行显示,超出省略号表示
重点:text-overflow: ellipsis;只对display:inline:起作用 例子: <span class="a">我说说<b class= ...
- Fedora16的双显卡切换问题
症状:笔记本是Acer 4745G,安装了Fedora16+Win7 x64的双系统,每次开机后,独立显卡的风扇就开始狂转,同时笔记本的发热量极大,左侧出风口简直烫手.... 问题:Acer 4745 ...
- Nginx的程序架构优化
解耦是开发人员中流行的有个名词,简单的说就是把一堆的程序代码按照业务用途分开,然后提供服务,例如:注册登录.上传.下载.浏览列表.商品内容页面.订单支付等都应该是独立的程序服务,只不过在客户端看来是一 ...