BZOJ2815 拓扑排序 + LCA
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的更多相关文章
- BZOJ2815:[ZJOI2012]灾难(拓扑排序,LCA)
Description 阿米巴是小强的好朋友. 阿米巴和小强在草原上捉蚂蚱.小强突然想,如果蚂蚱被他们捉灭绝了,那么吃蚂蚱的小鸟就会饿死,而捕食小鸟的猛禽也会跟着灭绝,从而引发一系列的生态灾难. 学过 ...
- 【bzoj2815】灾难[ZJOI2012](拓扑排序+lca)
题目传送门:http://www.lydsy.com/JudgeOnline/problem.php?id=2815 原版题解:http://fanhq666.blog.163.com/blog/st ...
- [BZOJ2815][ZJOI2012]灾难 灭绝树+拓扑排序+lca
灾难 [问题描述] 阿米巴是小强的好朋友. 阿米巴和小强在草原上捉蚂蚱.小强突然想,如果蚂蚱被他们捉灭绝了,那 么吃蚂蚱的小鸟就会饿死,而捕食小鸟的猛禽也会跟着灭绝,从而引发一系列的 生态灾难. 学过 ...
- 【题解】 [ZJOI2012]灾难 (拓扑排序+LCA)
懒得复制,戳我戳我 Solution: 这题思路很神奇,首先你要知道这个毁灭树是怎么保证实现的:一句话就是如果该节点要被破坏,他的所有父节点就要被破坏,也就只要所有父节点的LCA被破坏就可以,所以我们 ...
- 【BZOJ2815】[ZJOI2012]灾难 拓扑排序+LCA
[BZOJ2815][ZJOI2012]灾难 题目描述 阿米巴是小强的好朋友. 阿米巴和小强在草原上捉蚂蚱.小强突然想,果蚂蚱被他们捉灭绝了,那么吃蚂蚱的小鸟就会饿死,而捕食小鸟的猛禽也会跟着灭绝,从 ...
- 【bzoj2815】[ZJOI2012]灾难 拓扑排序+倍增LCA
题目描述(转自洛谷) 阿米巴是小强的好朋友. 阿米巴和小强在草原上捉蚂蚱.小强突然想,果蚂蚱被他们捉灭绝了,那么吃蚂蚱的小鸟就会饿死,而捕食小鸟的猛禽也会跟着灭绝,从而引发一系列的生态灾难. 学过生物 ...
- [BZOJ2815][ZJOI2012]灾难(拓扑排序/支配树)
支配树目前只见到这一个应用,那就不独分一类,直接作为拓扑排序题好了. 每个点向所有食物连边,定义fa[x]为x的支配点,即离x最近的点,满足若fa[x]灭绝,则x也要灭绝. 这样,将fa[x]向x连边 ...
- 洛谷P2597 [ZJOI2012] 灾难 [拓扑排序,LCA]
题目传送门 灾难 题目描述 阿米巴是小强的好朋友. 阿米巴和小强在草原上捉蚂蚱.小强突然想,如果蚂蚱被他们捉灭绝了,那么吃蚂蚱的小鸟就会饿死,而捕食小鸟的猛禽也会跟着灭绝,从而引发一系列的生态灾难. ...
- hihocoder 1343 : Stable Members【拓扑排序】
hihocoder #1343:题目 解释:一个学习小组,一共有N个学员,一个主管.每个学员都有自己的导师(一个或者多个),导师可以是其他学员也可以是主管.每周学员都要把自己的学习报告和收到的报告提交 ...
随机推荐
- [西安交大附中集训] d6 删边(cip)
B. 删边(cip.cpp/in/out 1S/256M) 题面 给出一个没有重边和自环的无向图,现在要求删除其中两条边,使得图仍然保持连通. 你的任务是计算有多少组不合法的选边方案.注意方案是无序二 ...
- sws_getContext函数参数介绍
原型: SwsContext *sws_getContext(int srcW, int srcH, enum AVPixelFormat srcFormat, int dstW, int dstH, ...
- Codeforces Round #432 Div. 1
A:大胆猜想合法点不会很多,于是暴力检验,一旦发现不合法就break,可以random_shuffle一下. #include<iostream> #include<cstdio&g ...
- PHP 事务写法
$md=new Model(); //创建事务 $md->startTrans(); //开始事务 $md->table("ym_xxx")->where(&qu ...
- CentOS7搭建配置SVN服务器
安装subversionyum install subversionsubversion安装在/bin目录检查一下subversion是否安装成功svnserve --version 建立版本库sub ...
- Hdoj 1003.Max Sum 题解
Problem Description Given a sequence a[1],a[2],a[3]......a[n], your job is to calculate the max sum ...
- edit 控件之隐藏光标
@2019-02-22 [小记] 禁止聚焦功能便可实现
- 「SCOI2014」方伯伯的商场之旅 解题报告
「SCOI2014」方伯伯的商场之旅 我一开始的想法会被两个相同的集合位置去重给搞死,不过应该还是可以写的,讨论起来老麻烦. 可以先钦定在\(1\)号点集合,然后往后调整一部分. 具体一点,通过前缀和 ...
- [APIO/CTSC 2007]数据备份(贪心+堆)
你在一家 IT 公司为大型写字楼或办公楼(offices)的计算机数据做备份.然而数据备份的工作是枯燥乏味的,因此你想设计一个系统让不同的办公楼彼此之间互相备份,而你则坐在家中尽享计算机游戏的乐趣. ...
- A/D和D/A的学习
从我们学到的知识了解到,我们的单片机是一个典型的数字系统.数字系统只能对输入的数字信号进行处理,其输出信号也是数字信号.但是在工业检测系统和日常生活中的许多物理量都是模拟量,比如温度.长度.压力.速度 ...