Description

阿米巴是小强的好朋友。

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

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

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

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

这个图没有环。

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

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

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

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

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

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

Input

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

号到 N。

接下来 N 行,每行描述了一个生物可以吃的其他生物的列表,格式为用空

格隔开的若干个数字,每个数字表示一种生物的标号,最后一个数字是 0 表示列

表的结束。

Output

输出文件catas.out包含N行,每行一个整数,表示每个生物的灾难值。

Sample Input

4 5
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)的更多相关文章

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

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

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

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

  3. 【bzoj2815】[ZJOI2012]灾难 拓扑排序+倍增LCA

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

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

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

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

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

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

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

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

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

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

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

  9. 【题解】 [ZJOI2012]灾难 (拓扑排序+LCA)

    懒得复制,戳我戳我 Solution: 这题思路很神奇,首先你要知道这个毁灭树是怎么保证实现的:一句话就是如果该节点要被破坏,他的所有父节点就要被破坏,也就只要所有父节点的LCA被破坏就可以,所以我们 ...

随机推荐

  1. 【Tomcat】JVM,Tomcat,Servlet,Tomcat中的应用。彻底弄懂这些概念之间的联系

    tomcat和tomcat中的应用(即webapps下的war包)是运行在同一个jvm中的,但分工不同. tomcat的角色是“调度员”,而你的应用的角色是“工作者”,tomcat处理一个请求的大致过 ...

  2. 虚拟机中安装完 CentOS7minimal 版本后无法联网的问题

    问题描述 安装完系统后无法上网,然后进入到目录 /etc/sysconfig/network-script 查看.发现只有一个 ifcfg-lo. 解决办法 这种情况是没有识别到网卡. 在 VMwar ...

  3. JAVA动态代理基础

    Java动态代理机制详解(JDK 和CGLIB,Javassist,ASM) 彻底理解JAVA动态代理 class文件简介及加载 Java编译器编译好Java文件之后,产生.class 文件在磁盘中. ...

  4. js-ES6学习笔记-Proxy(2)

    1.has方法用来拦截HasProperty操作,即判断对象是否具有某个属性时,这个方法会生效.典型的操作就是in运算符. var handler = { has (target, key) { if ...

  5. Ajax常见面试题 -- 前端面试题(二)

    1:什么是ajax?ajax作用是什么? 异步的javascript和xml AJAX 是一种用于创建快速动态网页的技术. ajax用来与后台交互   2:原生js ajax请求有几个步骤?分别是什么 ...

  6. React之小知识点总结

    总结react中常常被忽略的小知识点 1)即使state里设置成和之前的值一样,render也会重新渲染 2)父组件传给子组件的属性(props是只读的,在子组件中已在this.state里将属性赋值 ...

  7. 前端开发面试题-JavaScript(转载)

    本文由 本文的原作者markyun 收集总结. 介绍js的基本数据类型. Undefined.Null.Boolean.Number.String. ECMAScript 2015 新增:Symbol ...

  8. 如何在Oracle数据库中查看哪些用户在执行哪些SQL

    对于DBA来说,这是一个非常常见的问题,DBA需要找出以下问题: 1.哪些用户在跑哪些SQL? 2.一个特定的SQL是被哪个用户在执行? 3.一个特定的用户在跑哪些SQL? 从这些问题中可以很明显的看 ...

  9. DevExpress.XtraCharts曲线上的点所对应的坐标值

    private void chartControl_ObjectSelected(object sender, HotTrackEventArgs e) { e.Cancel = false; XYD ...

  10. node socket :10106无法加载或初始化请求的服务提供程序

    node socket :10106无法加载或初始化请求的服务提供程序 无端端的,不知道怎么回事,node突然就坏掉 了,应该是某些配置无意中改动了,问题如下: 目前能想到的解决办法就是:重置配置,用 ...