灭绝树学习小记

2023-11-20 19:50
文章标签 学习 小记 灭绝

本文主要是介绍灭绝树学习小记,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

灭绝树学习小记

Tags:图论


一、概述

听这名字特别酷对吧
不像一个Noip滚粗选手能学的东西
所以只能当一个搬运工了
orzlitble:https://blog.csdn.net/litble/article/details/83019578

灭绝树和支配树应该是一种东西
用于\(O((n+m)logn)\)或者\(O((n+m)\alpha)\)求解一类如下问题:

在一张捕食图上(从捕食者向被捕食者有连边),若某生物的所有食物都灭绝了,则该生物灭绝。
灭绝树便是此图的一种生成树,使得满足灭绝树上某点灭绝,该点子树内所有点都灭绝

二、实现方式

把图分成以下几种情况考虑

本身就是自己的灭绝树

DAG

  • [ZJOI2012]灾难
  • [Codeforces757F]Team Rocket Rises Again

分以下几步

  • 求出DAG的拓扑序
  • 照拓扑序,从出度为0的点开始,某点的灭绝树上父亲就是该点在DAG上的所有出点 在灭绝树上的LCA
  • 如果没有出度,连向一个虚拟点0方便计算

找LCA用倍增实现即可

一般有向图

例题:HDU4694 Important Sisters:求一般图每个点支配树上的祖先编号之和
\(orz\ Tarjan\)
首先把原图\(dfs\)一遍,求出\(dfn\)

半支配点

官方定义:\(semi[x]=min\{v |\)有路径\(v->v0->v1...->v_k->x\)使得\(dfn[v_i]>dfn[x]\)\(1<=i<=k\)成立\(\}\)\(min\)\(dfn\)最小
通俗一点:\(semi[x]\)\(x\)的路径,掐头去尾,都走的\(dfn\)大于\(x\)的点

画个图大概就是如下,\(dfn[]=\{0,1,2,3,4,5,7,6\}\)\(2->6->5\)掐头去尾的\(dfn\)都大于\(dfn[5]\)
o_%E7%81%AD%E7%BB%9D%E6%A0%911.png
重要性质:
以下祖先关系均指\(dfs\)树的祖先关系

  • 1.不在\(dfs\)树上的边一定是由\(dfn\)大的点指向\(dfn\)小的点
  • 2.\(semi[x]\)一定是\(x\)的祖先
  • 3.在\(dfs\)树上从\(semi[x]\)\(x\)连边,删掉其他边,灭绝关系不变

性感地理解就是:\(semi[x]\)\(x\)的路径相当于是在\(dfs\)树外有一条路,且\(semi[x]\)是离根最近的那个点,从\(semi[x]\)都走不到\(x\)了,那其他的点更走不到了

由此可以得出一种做法,求出\(semi\)后转DAG的做法,复杂度\(O(nlogn)\)

求半支配点

十分的巧妙
按照\(dfn\)序从大到小做,对于\(x\),枚举\(R\)存在\(R->x\)这条边

for(int w=n;w>=2;w--)
{int x=id[w],res=n;for(int i=rA.head[x];i;i=rA.a[i].next){int R=rA.a[i].to;//反图if(!dfn[R]) continue;//有可能root不能走到yif(dfn[R]<dfn[x]) res=min(res,dfn[R]);else find(R),res=min(res,dfn[semi[mn[R]]]);}//anc[x]表示x在dfs树上的父亲semi[x]=id[res];fa[x]=anc[x];B.link(semi[x],x);
}

其中\(find(R)\)表示路径压缩的带权并查集,维护\(R\)到其已经被搜过的祖先的 \(dfn\)的最小值\(mn[R]\),用\(semi[mn[R]]\)去更新\(semi[x]\)
然后例题就得到了一种\(O(nlog)\)的做法

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<queue>
#include<vector>
#include<cstring>
#define pb push_back
using namespace std;
const int N=1e5+10;
int n,m,ans[N],dfn[N],id[N],tot,dep[N];
int anc[N],fa[N],semi[N],mn[N],in[N],ff[20][N];
int q[N],top;
queue<int> Q;
vector<int> E[N];
struct Map
{struct edge {int next,to;}a[N<<1];int head[N],cnt;void reset(){cnt=0;memset(head,0,sizeof(head));}void link(int x,int y) {a[++cnt]=(edge){head[x],y};head[x]=cnt;}
}A,rA,B,C;
void reset()
{A.reset();rA.reset();B.reset();C.reset();tot=top=0;for(int i=1;i<=n;i++){dfn[i]=id[i]=ans[i]=in[i]=anc[i]=dep[i]=0;fa[i]=mn[i]=semi[i]=i;E[i].clear();for(int j=0;j<=18;j++) ff[j][i]=0;}
}
void dfs(int x,int fr)
{dfn[x]=++tot;id[tot]=x;anc[x]=fr;B.link(fr,x);for(int i=A.head[x];i;i=A.a[i].next)if(!dfn[A.a[i].to]) dfs(A.a[i].to,x);
}
void dfscalc(int x,int fr)
{ans[x]=x+ans[fr];for(int i=C.head[x];i;i=C.a[i].next)dfscalc(C.a[i].to,x);
}
int find(int x)
{if(x==fa[x]) return x;int tt=fa[x];fa[x]=find(fa[x]);if(dfn[semi[mn[tt]]]<dfn[semi[mn[x]]]) mn[x]=mn[tt];return fa[x];
}
int LCA(int x,int y)
{if(dep[x]<dep[y]) swap(x,y);int d=dep[x]-dep[y];for(int i=18;i>=0;i--) if(d&(1<<i)) x=ff[i][x];for(int i=18;i>=0;i--)if(ff[i][x]^ff[i][y])x=ff[i][x],y=ff[i][y];return x==y?x:ff[0][x];
}
void Work()
{dfs(n,0);for(int w=n;w>=2;w--){int x=id[w],res=n;if(!x) continue;for(int i=rA.head[x];i;i=rA.a[i].next){int R=rA.a[i].to;if(!dfn[R]) continue;if(dfn[R]<dfn[x]) res=min(res,dfn[R]);else find(R),res=min(res,dfn[semi[mn[R]]]);}semi[x]=id[res];fa[x]=anc[x];B.link(semi[x],x);}for(int x=1;x<=n;x++)for(int i=B.head[x];i;i=B.a[i].next)in[B.a[i].to]++,E[B.a[i].to].pb(x);for(int x=1;x<=n;x++) if(!in[x]) Q.push(x);while(!Q.empty()){int x=Q.front();Q.pop();q[++top]=x;for(int i=B.head[x];i;i=B.a[i].next)if(!--in[B.a[i].to]) Q.push(B.a[i].to);}for(int i=1;i<=top;i++){int x=q[i],f=0,l=E[x].size();if(l) f=E[x][0];for(int j=1;j<l;j++) f=LCA(f,E[x][j]);ff[0][x]=f;dep[x]=dep[f]+1;C.link(f,x);for(int p=1;p<=18;p++) ff[p][x]=ff[p-1][ff[p-1][x]];}ans[0]=0;dfscalc(n,0);
}
int main()
{while(scanf("%d%d",&n,&m)!=EOF){reset();for(int i=1,x,y;i<=m;i++)scanf("%d%d",&x,&y),A.link(x,y),rA.link(y,x);Work();for(int i=1;i<n;i++) printf("%d ",ans[i]);printf("%d\n",ans[n]);}return 0;
}

更高效的做法

性质
\(idom[x]\)表示\(x\)的支配点(灭绝树/支配树上的父亲)

  • 若x是y的祖先,则要么\(x\)\(idom[y]\)的祖先,要么\(idom[y]\)\(idom[x]\)的祖先

可以这样性感地理解:如果\(x\)是祖先,那么\(x\)的食物来源(指向\(x\)的边)就少,相对来说灭绝掉\(x\)更容易,那么\(idom[x]\)会相应地靠近\(x\),同理\(y\)什么都吃所以夸张地说就是要把草给灭绝了\(y\)才会灭绝



然后看不懂了。。真的不可理解了。。而且发现上边一般图的做法我并不一定理解到位
丢个链接甩锅吧
https://www.cnblogs.com/fenghaoran/p/dominator_tree.html
应该很少会有这种毒瘤玩意,记得\(O(nlogn)\)的做法就好了,毕竟路径压缩并查集是可以被卡成\(O(nlogn)\)的:http://www.cnblogs.com/meowww/p/6475952.html

转载于:https://www.cnblogs.com/xzyxzy/p/10213341.html

这篇关于灭绝树学习小记的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/397032

相关文章

HarmonyOS学习(七)——UI(五)常用布局总结

自适应布局 1.1、线性布局(LinearLayout) 通过线性容器Row和Column实现线性布局。Column容器内的子组件按照垂直方向排列,Row组件中的子组件按照水平方向排列。 属性说明space通过space参数设置主轴上子组件的间距,达到各子组件在排列上的等间距效果alignItems设置子组件在交叉轴上的对齐方式,且在各类尺寸屏幕上表现一致,其中交叉轴为垂直时,取值为Vert

Ilya-AI分享的他在OpenAI学习到的15个提示工程技巧

Ilya(不是本人,claude AI)在社交媒体上分享了他在OpenAI学习到的15个Prompt撰写技巧。 以下是详细的内容: 提示精确化:在编写提示时,力求表达清晰准确。清楚地阐述任务需求和概念定义至关重要。例:不用"分析文本",而用"判断这段话的情感倾向:积极、消极还是中性"。 快速迭代:善于快速连续调整提示。熟练的提示工程师能够灵活地进行多轮优化。例:从"总结文章"到"用

【前端学习】AntV G6-08 深入图形与图形分组、自定义节点、节点动画(下)

【课程链接】 AntV G6:深入图形与图形分组、自定义节点、节点动画(下)_哔哩哔哩_bilibili 本章十吾老师讲解了一个复杂的自定义节点中,应该怎样去计算和绘制图形,如何给一个图形制作不间断的动画,以及在鼠标事件之后产生动画。(有点难,需要好好理解) <!DOCTYPE html><html><head><meta charset="UTF-8"><title>06

学习hash总结

2014/1/29/   最近刚开始学hash,名字很陌生,但是hash的思想却很熟悉,以前早就做过此类的题,但是不知道这就是hash思想而已,说白了hash就是一个映射,往往灵活利用数组的下标来实现算法,hash的作用:1、判重;2、统计次数;

零基础学习Redis(10) -- zset类型命令使用

zset是有序集合,内部除了存储元素外,还会存储一个score,存储在zset中的元素会按照score的大小升序排列,不同元素的score可以重复,score相同的元素会按照元素的字典序排列。 1. zset常用命令 1.1 zadd  zadd key [NX | XX] [GT | LT]   [CH] [INCR] score member [score member ...]

【机器学习】高斯过程的基本概念和应用领域以及在python中的实例

引言 高斯过程(Gaussian Process,简称GP)是一种概率模型,用于描述一组随机变量的联合概率分布,其中任何一个有限维度的子集都具有高斯分布 文章目录 引言一、高斯过程1.1 基本定义1.1.1 随机过程1.1.2 高斯分布 1.2 高斯过程的特性1.2.1 联合高斯性1.2.2 均值函数1.2.3 协方差函数(或核函数) 1.3 核函数1.4 高斯过程回归(Gauss

【学习笔记】 陈强-机器学习-Python-Ch15 人工神经网络(1)sklearn

系列文章目录 监督学习:参数方法 【学习笔记】 陈强-机器学习-Python-Ch4 线性回归 【学习笔记】 陈强-机器学习-Python-Ch5 逻辑回归 【课后题练习】 陈强-机器学习-Python-Ch5 逻辑回归(SAheart.csv) 【学习笔记】 陈强-机器学习-Python-Ch6 多项逻辑回归 【学习笔记 及 课后题练习】 陈强-机器学习-Python-Ch7 判别分析 【学

系统架构师考试学习笔记第三篇——架构设计高级知识(20)通信系统架构设计理论与实践

本章知识考点:         第20课时主要学习通信系统架构设计的理论和工作中的实践。根据新版考试大纲,本课时知识点会涉及案例分析题(25分),而在历年考试中,案例题对该部分内容的考查并不多,虽在综合知识选择题目中经常考查,但分值也不高。本课时内容侧重于对知识点的记忆和理解,按照以往的出题规律,通信系统架构设计基础知识点多来源于教材内的基础网络设备、网络架构和教材外最新时事热点技术。本课时知识

线性代数|机器学习-P36在图中找聚类

文章目录 1. 常见图结构2. 谱聚类 感觉后面几节课的内容跨越太大,需要补充太多的知识点,教授讲得内容跨越较大,一般一节课的内容是书本上的一章节内容,所以看视频比较吃力,需要先预习课本内容后才能够很好的理解教授讲解的知识点。 1. 常见图结构 假设我们有如下图结构: Adjacency Matrix:行和列表示的是节点的位置,A[i,j]表示的第 i 个节点和第 j 个

Node.js学习记录(二)

目录 一、express 1、初识express 2、安装express 3、创建并启动web服务器 4、监听 GET&POST 请求、响应内容给客户端 5、获取URL中携带的查询参数 6、获取URL中动态参数 7、静态资源托管 二、工具nodemon 三、express路由 1、express中路由 2、路由的匹配 3、路由模块化 4、路由模块添加前缀 四、中间件