[ZJOI2012] 灾难 题解
爵士好提
Solution
定义\(u\)控制\(v\)当且仅当\(u\)死后\(v\)也会死
把图建出来,从食物向消费者连边
我们不难想到只能先处理食物,再处理消费者,所以先上个拓扑排序
想一想暴力怎么做,对于每个点我们考虑状压维护这个点受哪些点控制,暴力合并即可。
但显然,这个暴力的复杂度是\(O(n^2)\)的。
考虑到控制的一个性质:若\(x\)控制\(z\)而\(y\)同样控制\(z\),则要么\(x\)控制\(y\),要么\(y\)控制\(x\)
我们不妨考虑根据控制的关系建出一棵树来,\(u\)是\(v\)的祖先当且仅当\(u\)控制\(v\),显然,一个点的答案就是这个点在树上对应点节点为根的子树大小\(-1\)
怎么建出这棵树?
接下来的问题就很显然了,我们考虑每遍历到一条边\((u,v)\)都用\(u\)去更新\(v\)的父亲,具体过程用\(\text{LCA}\)算法即可,我使用倍增实现,需要在线维护倍增数组
Code
#include <cstdio>
#include <iostream>
using namespace std;
inline int read() {
int res = 0, flag = 0; char ch = getchar();
for(; !isdigit(ch); ch = getchar()) if(ch == '-') flag = 1;
for(; isdigit(ch); ch = getchar()) res = (res << 1) + (res << 3) + (ch ^ 48);
if(flag) res = ~res + 1; return res;
}
const int N = 70000;
int n, tail, head, que[N];
int la[N], la1[N], tot, tot1, d[N], fa[N][20], dep[N], sz[N];
struct Edge {int to, nxt;} e[2000010], e1[100000];
inline void build(int u, int v) {e[++tot] = (Edge) {v, la[u]}, la[u] = tot, ++d[v];}
inline void build1(int u, int v) {e1[++tot1] = (Edge) {v, la1[u]}, la1[u] = tot1;}
void update(int x) {
if(x == n + 1) return ;
build1(fa[x][0], x), dep[x] = dep[fa[x][0]] + 1;
for(int i = 1; i <= 17; ++i)
fa[x][i] = fa[fa[x][i - 1]][i - 1];
return ;
}
inline int getlca(int x, int y) {
if(dep[x] < dep[y]) swap(x, y);
for(int i = 17; i + 1; --i)
if(dep[fa[x][i]] >= dep[y]) x = fa[x][i];
if(x == y) return x;
for(int i = 17; i + 1; --i)
if(fa[x][i] != fa[y][i]) x = fa[x][i], y = fa[y][i];
return fa[x][0];
}
void work(int x, int y) {fa[x][0] = (fa[x][0] ? getlca(fa[x][0], y) : y);}
void dfs(int k) {
sz[k] = 1;
for(int v, i = la1[k]; i; i = e1[i].nxt) {
v = e1[i].to;
dfs(v), sz[k] += sz[v];
}
return ;
}
void solve() {
que[tail = 1] = n + 1, dep[n + 1] = 1;
while(++head <= tail) {
update(que[head]);
for(int v, i = la[que[head]]; i; i = e[i].nxt) {
v = e[i].to;
--d[v], work(v, que[head]);
if(!d[v]) que[++tail] = v;
}
}
dfs(n + 1);
}
int main() {
n = read();
for(int v, u = 1; u <= n; ++u) {
v = read();
while(v) build(v, u), v = read();
}
for(int i = 1; i <= n; ++i) if(!d[i]) build(n + 1, i);
solve();
for(int i = 1; i <= n; ++i) printf("%d\n",sz[i] - 1);
}
[ZJOI2012] 灾难 题解的更多相关文章
- 【BZOJ2815】[ZJOI2012]灾难 拓扑排序+LCA
[BZOJ2815][ZJOI2012]灾难 题目描述 阿米巴是小强的好朋友. 阿米巴和小强在草原上捉蚂蚱.小强突然想,果蚂蚱被他们捉灭绝了,那么吃蚂蚱的小鸟就会饿死,而捕食小鸟的猛禽也会跟着灭绝,从 ...
- [洛谷P2597] [ZJOI2012]灾难
洛谷题目链接:[ZJOI2012]灾难 题目描述 阿米巴是小强的好朋友. 阿米巴和小强在草原上捉蚂蚱.小强突然想,如果蚂蚱被他们捉灭绝了,那么吃蚂蚱的小鸟就会饿死,而捕食小鸟的猛禽也会跟着灭绝,从而引 ...
- Luogu_2597_[ZJOI2012]灾难 倍增lca + 构造
Luogu_2597_[ZJOI2012]灾难 倍增lca + 构造 题意: 我们用一种叫做食物网的有向图来描述生物之间的关系:一个食物网有N个点,代表N种生物,如果生物x可以吃生物y,那么从y向x连 ...
- 1321. [ZJOI2012] 灾难
1321. [ZJOI2012] 灾难 ★★☆ 输入文件:catas.in 输出文件:catas.out 简单对比时间限制:1 s 内存限制:128 MB [问题描述] 阿米巴是小强的 ...
- 洛谷 P2597 [ZJOI2012]灾难 解题报告
P2597 [ZJOI2012]灾难 题目描述 阿米巴是小强的好朋友. 阿米巴和小强在草原上捉蚂蚱.小强突然想,如果蚂蚱被他们捉灭绝了,那么吃蚂蚱的小鸟就会饿死,而捕食小鸟的猛禽也会跟着灭绝,从而引发 ...
- P2597 [ZJOI2012]灾难——拓扑,倍增,LCA
最近想学支配树,但是基础还是要打好了的: P2597 [ZJOI2012]灾难 这道题是根据食物链链接出一个有向图的关系,求一个物种的灭绝会连带几种物种的灭绝: 求得就是一个点能支配几个点: 如果一个 ...
- 【题解】 [ZJOI2012]灾难 (拓扑排序+LCA)
懒得复制,戳我戳我 Solution: 这题思路很神奇,首先你要知道这个毁灭树是怎么保证实现的:一句话就是如果该节点要被破坏,他的所有父节点就要被破坏,也就只要所有父节点的LCA被破坏就可以,所以我们 ...
- 【bzoj2815】[ZJOI2012]灾难 拓扑排序+倍增LCA
题目描述(转自洛谷) 阿米巴是小强的好朋友. 阿米巴和小强在草原上捉蚂蚱.小强突然想,果蚂蚱被他们捉灭绝了,那么吃蚂蚱的小鸟就会饿死,而捕食小鸟的猛禽也会跟着灭绝,从而引发一系列的生态灾难. 学过生物 ...
- P2597 [ZJOI2012]灾难
\(\color{#0066ff}{ 题目描述 }\) 阿米巴是小强的好朋友. 阿米巴和小强在草原上捉蚂蚱.小强突然想,如果蚂蚱被他们捉灭绝了,那么吃蚂蚱的小鸟就会饿死,而捕食小鸟的猛禽也会跟着灭绝, ...
随机推荐
- 2550--HashMap源码解析
JDK版本 1.8 结构: HashMap实现了Map Cloneable Serializable接口: 基础了AbstractMap类,AbstractMap提供一些通用方法,如put remov ...
- HTML表单学习
HTML表单学习 前言 HTML基础学习会由HTML基础标签学习.HTML表单学习和一张思维导图总结HTML基础三篇文章构成,文章中博主会提取出重点常用的知识和经常出现的bug,提高学习的效率,后续会 ...
- C 语言 时间函数使用技巧(汇总)
time.h 头文件 是 C 语言中 有关 时间的函数所储存的头文件 #include <time.h> 在介绍时间函数用法之前,我们首先要了解在 time.h 头文件中已经声明了的一个结 ...
- 使用.NET简单实现一个Redis的高性能克隆版(七-完结)
译者注 该原文是Ayende Rahien大佬业余自己在使用C# 和 .NET构建一个简单.高性能兼容Redis协议的数据库的经历. 首先这个"Redis"是非常简单的实现,但是他 ...
- 达人专栏 | 还不会用 Apache Dolphinscheduler?大佬用时一个月写出的最全入门教程【三】
作者 | 欧阳涛 招联金融大数据开发工程师 02 Master启动流程 2.10 WorkFlowExecutorThread 里执行 Submit StandByTask 方法 SubmitStan ...
- 【Java】学习路径46-两种创建多线程的方法、以及在匿名内部类创建线程
两种方法: 1.创建一个继承自Thread的线程类,然后再main(不限)中构造这个线程类对象.方法在之前讲过. 2.创建一个使用Runnable接口的线程类,然后在main(不限)中构造这个Runn ...
- KingbaseES行转列(PIVOT)
如果以交叉表格式显示,则商业智能查询返回的数据通常是最有用的.SELECT语句的pivot_.数据透视是数据仓库中的一项关键技术.在其中,您可以将多行输入转换为数据仓库中较少且通常较宽的行.进行数据透 ...
- Go常见
GO基础语法 方法或函数调用时,传入参数一般都是值复制,除非是map.slice.channel.指针类型是引用传递 短的变量声明(Short Variable Declarations),即自动推导 ...
- Java 热更新 Groovy 实践及踩坑指南
Groovy 是什么? Apache的Groovy是Java平台上设计的面向对象编程语言.这门动态语言拥有类似Python.Ruby和Smalltalk中的一些特性,可以作为Java平台的脚本语言使用 ...
- H5页面调用admob激励视频,用户获取奖励
应用前提条件 使用 Android Studio 3.2 或更高版本 确保您应用的 build 文件使用以下值: minSdkVersion 为 16 或更高版本 compileSdkVersion ...