https://www.lydsy.com/JudgeOnline/problem.php?id=2815

作为一个DAG图,结点之间又有这么明显的等级之分,很容易想到的是拓扑排序。

但是不管是正向的拓扑排序还是逆向的拓扑排序感觉都不是特别容易的能解决这个问题。

但事实上只要知道一个十分关键的点:一个物种会灭绝的必要条件是当且仅当另一个物种灭绝。

例如样例给的图片当中,小强的灭绝仅和草是否灭绝有关,和牛羊无关。

因此事实上这个图的关系可以变为一棵树的关系,一个点会灭绝当且仅当他的祖先灭绝。

怎么确定一个点的父亲结点?考虑动态建树,以最底层的食物为起点开始拓扑排序,一个结点被访问意味着它所有的食物已经被加入树中,那么他的父亲就是他所有食物的LCA


最后求一个树的前缀和就可以了

一个小细节是倍增LCA需要一边建树一边维护稀疏表。

#include <map>
#include <set>
#include <ctime>
#include <cmath>
#include <queue>
#include <stack>
#include <vector>
#include <string>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <sstream>
#include <iostream>
#include <algorithm>
#include <functional>
using namespace std;
#define For(i, x, y) for(int i=x;i<=y;i++)
#define _For(i, x, y) for(int i=x;i>=y;i--)
#define Mem(f, x) memset(f,x,sizeof(f))
#define Sca(x) scanf("%d", &x)
#define Sca2(x,y) scanf("%d%d",&x,&y)
#define Sca3(x,y,z) scanf("%d%d%d",&x,&y,&z)
#define Scl(x) scanf("%lld",&x);
#define Pri(x) printf("%d\n", x)
#define Prl(x) printf("%lld\n",x);
#define CLR(u) for(int i=0;i<=N;i++)u[i].clear();
#define LL long long
#define ULL unsigned long long
#define mp make_pair
#define PII pair<int,int>
#define PIL pair<int,long long>
#define PLL pair<long long,long long>
#define pb push_back
#define fi first
#define se second
typedef vector<int> VI;
int read(){int x = ,f = ;char c = getchar();while (c<'' || c>''){if (c == '-') f = -;c = getchar();}
while (c >= ''&&c <= ''){x = x * + c - '';c = getchar();}return x*f;}
const double eps = 1e-;
const int maxn = 1e5 + ;
const int INF = 0x3f3f3f3f;
const int mod = 1e9 + ;
int N,M,K;
struct Edge{
int to,next;
}edge[],redge[maxn],tedge[maxn];
int head[maxn],tot;
int rhead[maxn],rtot;
int thead[maxn],ttot;
int pre[maxn];
void init(){
for(int i = ; i <= N ; i ++) rhead[i] = thead[i] = head[i] = -;
tot = rtot = ttot = ;
}
void add(int u,int v){
edge[tot].to = v;
edge[tot].next = head[u];
head[u] = tot++;
redge[rtot].to = u;
redge[rtot].next = rhead[v];
rhead[v] = rtot++;
}
void tadd(int u,int v){
tedge[ttot].to = v;
tedge[ttot].next = thead[u];
thead[u] = ttot++;
}
const int SP = ;
int ind[maxn];
int pa[maxn][SP],dep[maxn];
void dfs(int u,int la){
pre[u] = ;
for(int i = thead[u]; ~i ; i = tedge[i].next){
int v = tedge[i].to;
if(v == la) continue;
dfs(v,u);
pre[u] += pre[v] + ;
}
}
int lca(int u,int v){
if(dep[u] < dep[v]) swap(u,v);
int t = dep[u] - dep[v];
for(int i = ; i < SP; i ++) if(t & ( << i)) u = pa[u][i];
for(int i = SP - ; i >= ; i --){
int uu = pa[u][i], vv = pa[v][i];
if(uu != vv){
u = uu;
v = vv;
}
}
return u == v ? u : pa[u][];
}
int main(){
Sca(N); init();
for(int i = ; i <= N ; i ++){
int x;
while(~scanf("%d",&x) && x){
add(i,x);
ind[i]++;
}
}
int root = ;
pa[root][] = ; dep[root] = ;
for(int i = ; i < SP; i ++) pa[root][i] = pa[pa[root][i - ]][i - ];
queue<int>Q;
for(int i = ; i <= N ; i ++){
if(!ind[i]){
add(i,root);
Q.push(i);
}
}
while(!Q.empty()){
int u = Q.front(); Q.pop();
int fa = -;
for(int i = head[u]; ~i ; i = edge[i].next){
int v = edge[i].to;
if(~fa) fa = lca(fa,v);
else fa = v;
}
tadd(fa,u);
pa[u][] = fa; dep[u] = dep[fa] + ;
for(int i = ; i < SP ; i ++) pa[u][i] = pa[pa[u][i - ]][i - ];
for(int i = rhead[u]; ~i ; i = redge[i].next){
int v = redge[i].to;
ind[v]--;
if(!ind[v]) Q.push(v);
}
}
dfs(root,-);
for(int i = ; i <= N ; i ++) Pri(pre[i]);
return ;
}

BZOJ2815 拓扑排序 + LCA的更多相关文章

  1. BZOJ2815:[ZJOI2012]灾难(拓扑排序,LCA)

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

  9. hihocoder 1343 : Stable Members【拓扑排序】

    hihocoder #1343:题目 解释:一个学习小组,一共有N个学员,一个主管.每个学员都有自己的导师(一个或者多个),导师可以是其他学员也可以是主管.每周学员都要把自己的学习报告和收到的报告提交 ...

随机推荐

  1. codeforces616B

    Dinner with Emma CodeForces - 616B Jack decides to invite Emma out for a dinner. Jack is a modest st ...

  2. Power Spectral Density

    对于一个特定的信号来说,有时域与频域两个表达形式,时域表现的是信号随时间的变化,频域表现的是信号在不同频率上的分量.在信号处理中,通常会对信号进行傅里叶变换得到该信号的频域表示,从而得到信号在频域上的 ...

  3. mysql-语法大全

    DDL语句 库 创建 create database 库名 charset utf8; 删除 drop database 库名; 修改 alter database 库名 charset latin; ...

  4. 进程创建fork()

    简单进程创建例子: #include <stdio.h> #include <sys/types.h> #include <sys/wait.h> #include ...

  5. github-share报错无法读取远程仓库

    报错:github Could not read from remote repository 1.github创建仓库成功,而push报告此错误 2.考虑远程仓库名与本地项目名/文件夹名不匹配 3. ...

  6. HUST 1555 数学作业

    参考自:https://www.cnblogs.com/ECJTUACM-873284962/p/6394892.html 1555 - A Math Homework 时间限制:1秒 内存限制:12 ...

  7. 二分图最小点覆盖König定理的简单证明 (加入自己理解)

    第一次更改:http://blog.sina.com.cn/s/blog_51cea4040100h152.html 讲的更细致 增广路:https://blog.csdn.net/qq_374572 ...

  8. HDU1505 City Game(算竞进阶习题)

    写了1506顺便写下1505.. 还是求矩形面积,不过要预处理一下以每一个F为底的高度,然后想左右扩展到最大长度即为矩形的长.. 计算方法有点绕,令l[i]表示i的左边界,那么初始化l[i] = i. ...

  9. Random Maze HDU - 4067(预定义状态建边(贪心建边))

    Random Maze Time Limit: 10000/3000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)Tota ...

  10. 【洛谷U20626】gemo 容斥 FWT 高斯消元

    题目大意 给你一个无向图,有\(m\)个询问,每次给你一个点\(x\)和一个点集\(S\),问你从\(x\)开始走,每次从一个点随机的走到与这个点相邻的点,问你访问\(S\)中每个点至少一次的期望步数 ...