【学习笔记】支配树基础理论

2023-10-28 12:28

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

摘抄自 oi-wiki 。

Part 1

考虑在任意 有向图 上钦定一个入口节点 s s s,对于一个节点 u u u,若从 s s s u u u的每一条路径都经过某一个节点 v v v,那么称 v v v支配 u u u,记作 v dom ⁡ u v\operatorname{dom}u vdomu

对于从 s s s出发无法到达的结点,讨论其支配关系是没有意义的,因此假设 s s s能到达图上任何一个节点

引理1: s s s是所有节点的支配点;任意一个节点都是其自身的支配点

引理2:仅考虑简单路径得出的支配关系与所有路径得出的关系相同

引理3:如果 u dom ⁡ v u\operatorname{dom}v udomv v dom ⁡ w v\operatorname{dom}w vdomw,则 u dom ⁡ w u\operatorname{dom}w udomw

引理4:如果 u dom ⁡ v , v dom ⁡ u u\operatorname{dom}v,v\operatorname{dom}u udomvvdomu,则 u = v u=v u=v

引理5:若 u ≠ v ≠ w u\ne v\ne w u=v=w u dom ⁡ w u\operatorname{dom}w udomw v dom ⁡ w v\operatorname{dom}w vdomw,则有 u dom ⁡ v u\operatorname{dom}v udomv v dom ⁡ u v\operatorname{dom}u vdomu

证明:考虑一条 s → u → v → w s\to u\to v\to w suvw的路径,若 u u u不支配 v v v,则存在一条 s → v → w s\to v\to w svw的路径,与 u dom ⁡ w u\operatorname{dom}w udomw矛盾(注意我们只考虑简单路径的情况)

将任意节点 u u u的支配点中,除自身外与自己距离最近的节点 v v v称作 u u u的直接支配点,记作 idom ⁡ ( u ) = v \operatorname{idom}(u)=v idom(u)=v

比较直观的理解:设 u u u的支配点集为 { s 1 , s 2 , . . . , s k } \{s_1,s_2,...,s_k\} {s1,s2,...,sk},则一定存在一条路径 s → s 1 → s 2 → . . . → s k → u s\to s_1\to s_2\to ...\to s_k\to u ss1s2...sku,显然 s k s_k sk就是 u u u的直接支配点。

将除 s s s外每一个节点 u u u idom ⁡ ( u ) \operatorname{idom}(u) idom(u) u u u连边,我们就得到了一颗支配树

结论:对于一个节点 u u u的支配点集 S S S,若 v ∈ S v\in S vS满足 ∀ w ∈ S \ { u , v } , w dom ⁡ v \forall w\in S\ \backslash \ \{u,v\},w\operatorname{dom}v wS \ {u,v},wdomv,则 idom ⁡ ( u ) = v \operatorname{idom}(u)=v idom(u)=v(结合前面的理解不难证明,这个可能构造题会用到)

Part 2

对于 D A G DAG DAG,我们可以直接根据拓扑序求解。

引理6:在有向图上, v dom ⁡ u v\operatorname{dom}u vdomu当且仅当 ∀ w ∈ p r e ( u ) , v dom ⁡ w \forall w\in pre(u),v\operatorname{dom} w wpre(u),vdomw

因此, u u u的支配点一定是其所有前驱节点在支配树上的公共祖先。使用 L C A LCA LCA算法即可解决。

Part 3

求解任意有向图中支配树的方法:

约定这里 w → v w\to v wv指的是存在 DFS 树上从 w w w v v v的路径。注意这个表述并不严谨,更严谨的记号可以参考 这篇博客。后文一些引理的证明也 参考了这篇博客

首先从 s s s出发对有向图进行 DFS ,所经过的点和边形成了一棵树 T T T。令 d f n ( u ) dfn(u) dfn(u)表示节点 u u u第几个被遍历到;定义 u < v u<v u<v当且仅当 d f n ( u ) < d f n ( v ) dfn(u)<dfn(v) dfn(u)<dfn(v)

引理7(路径引理):如果两个点 v , w v,w v,w满足 v ≤ w v\le w vw,那么任意 v v v w w w的路径经过 v , w v,w v,w的公共祖先(不一定是 L C A LCA LCA

证明主要是利用横叉边一定是从大的点到小的点。

定义节点 u u u的半支配点为,从这个节点 v v v出发存在一条路径,路径上除了 u , v u,v u,v之外的每个节点都大于 u u u的结点中最小的那一个,记作 sdom ⁡ ( u ) \operatorname{sdom}(u) sdom(u)

引理8:对于任意节点 u u u sdom(u) < u \text{sdom(u)}<u sdom(u)<u

显然 f a ( u ) < u fa(u)<u fa(u)<u,并且是合法的半支配点。

引理9:对于任意节点 u u u idom(u) \text{idom(u)} idom(u)是其在 T T T上的祖先

引理10:对于任意节点 u u u sdom ( u ) \text{sdom}(u) sdom(u)是其在 T T T上的祖先

如果 v v v不是 u u u的祖先,并且 v < u v<u v<u,那么 v v v u u u的路径一定经过 u , v u,v u,v的公共祖先(路径引理),不满足 v v v是支配点的条件。

引理11:对于任意节点 u u u idom ( u ) \text{idom}(u) idom(u) sdom ( u ) \text{sdom}(u) sdom(u)的祖先

引理12:对于任意节点 u ≠ v u\ne v u=v满足 v v v u u u的祖先,则要么有 v v v idom(u) \text{idom(u)} idom(u)的祖先,要么 idom(u) \text{idom(u)} idom(u) idom ( v ) \text{idom}(v) idom(v)的祖先

证明:对于任意在 v v v idom ( v ) \text{idom}(v) idom(v)之间的节点 w w w,一定存在一条不经过 w w w的,从 s s s idom ( v ) \text{idom}(v) idom(v)再到 v v v的路径。因此这些节点一定不是 idom(u) \text{idom(u)} idom(u),因此 idom(u) \text{idom(u)} idom(u)要么是 v v v的后代,要么是 idom(v) \text{idom(v)} idom(v)的祖先

引理13: sdom ( u ) = min ⁡ ( v ∣ ( v , u ) ∈ E , v < w ∪ sdom ( w ) ∣ w > u , ∃ ( v , u ) ∈ E , w → v ) \text{sdom}(u)=\min(v|(v,u)\in E,v<w\cup \text{sdom}(w)|w>u,\exist (v,u)\in E,w\to v) sdom(u)=min(v(v,u)E,v<wsdom(w)w>u,(v,u)E,wv)

可以从大到小枚举点,用带权并查集维护,从而求得所有点的半支配点。

引理14:对于任意 u ≠ r u\ne r u=r,如果所有 sdom(u) \text{sdom(u)} sdom(u) u u u之间(不包括 sdom(u) \text{sdom(u)} sdom(u))的点 v v v满足 sdom(v) ≥ sdom(u) \text{sdom(v)}\ge \text{sdom(u)} sdom(v)sdom(u),那么 idom(u) = sdom(u) \text{idom(u)}=\text{sdom(u)} idom(u)=sdom(u)

证明:只需证明 sdom(u) \text{sdom(u)} sdom(u)支配 u u u即可。考虑任意 s s s w w w的路径,取上面最后一个编号小于 sdom(u) \text{sdom(u)} sdom(u) x x x,则一定存在 y y y满足 y y y sdom(u) \text{sdom(u)} sdom(u) u u u之间。同理,考虑取最小的的 y y y,如果 y y y不是 sdom(u) \text{sdom(u)} sdom(u),那么根据条件, sdom(y) ≥ sdom(u) \text{sdom(y)}\ge \text{sdom(u)} sdom(y)sdom(u),所以 x x x不可能是 sdom(y) \text{sdom(y)} sdom(y),因此从 x x x y y y的路径上也存在一个 sdom(y) \text{sdom(y)} sdom(y) y y y之间的节点 w w w(这与之前的推理是一样的),这与 y y y最小矛盾。

这个结论比较重要,能让我们比较直观的感受到半支配点的作用。

引理15:对于任意 u u u,令 v v v sdom(u) \text{sdom(u)} sdom(u) u u u之间(不包括 sdom(u) \text{sdom(u)} sdom(u) sdom(v) \text{sdom(v)} sdom(v)最小的一个,并且 sdom(v) ≤ sdom(u) \text{sdom(v)}\le \text{sdom(u)} sdom(v)sdom(u),那么 idom(u) = idom(v) \text{idom(u)}=\text{idom(v)} idom(u)=idom(v)

证明:条件可以写成 sdom(v) → sdom(u) → v → u \text{sdom(v)}\to \text{sdom(u)}\to v\to u sdom(v)sdom(u)vu

由引理12可知 idom(u) → idom(v) \text{idom(u)}\to \text{idom(v)} idom(u)idom(v) v → idom(u) v\to \text{idom(u)} vidom(u),排除后面那种(引理11),只需证明 idom(v) \text{idom(v)} idom(v)支配 u u u。这是比较显然的。

引理16:对于任意 u u u,令 v v v sdom ( u ) \text{sdom}(u) sdom(u) u u u之间(不包括 sdom(u) \text{sdom(u)} sdom(u) sdom ( v ) \text{sdom}(v) sdom(v)最小的一个,则:

idom(u) = { sdom(u) sdom(v) = sdom(u) idom(v) sdom(v) < sdom(u) \text{idom(u)}= \begin{cases} \text{sdom(u)}& \text{sdom(v)}=\text{sdom(u)} \\ \text{idom(v)}&\text{sdom(v)}<\text{sdom(u)} \end{cases} idom(u)={sdom(u)idom(v)sdom(v)=sdom(u)sdom(v)<sdom(u)

说白了就是前两个引理。

可以发现求 v v v的过程和求半支配点是类似的,因此当从大到小处理到 sdom(u) \text{sdom(u)} sdom(u)的时候就可以顺便求出 u u u对应的信息。最后再从小到大遍历一遍即可。

复杂度 O ( n + m ) O(n+m) O(n+m)。非常高效。和SAM一样

吐槽:oi-wiki上的写法是错的,会被叉。网上的代码就没几个靠谱的。。。

#include<bits/stdc++.h>
#define ll long long
#define fi first
#define se second
#define pb push_back
#define inf 0x3f3f3f3f
using namespace std;
const int N=2e5+5;
int n,m,mn[N],dfn[N],num,ps[N],idm[N],sdm[N],fa[N],fth[N],sz[N];
vector<int>G[N],G2[N],G3[N],G4[N];
void dfs(int u){dfn[u]=++num,ps[num]=u;for(auto v:G[u]){if(!dfn[v])fth[v]=u,dfs(v);}
}
int find(int x){if(fa[x]==x)return x;int tmp=fa[x];fa[x]=find(fa[x]);if(dfn[sdm[mn[tmp]]]<dfn[sdm[mn[x]]]){mn[x]=mn[tmp];}return fa[x];
}
void solve(){dfs(1);for(int i=1;i<=n;i++)fa[i]=sdm[i]=mn[i]=i,idm[i]=1;for(int i=num;i>=2;i--){int u=ps[i],res=inf;for(auto v:G2[u]){if(dfn[v]<dfn[u]){res=min(res,dfn[v]);}else{find(v);res=min(res,dfn[sdm[mn[v]]]);}}//u=fth[u];for(auto v:G3[u]){find(v);if(sdm[mn[v]]==sdm[v]){idm[v]=u;}else{idm[v]=mn[v];}}sdm[u]=ps[res];G3[sdm[u]].pb(u);fa[u]=fth[u];}for(int i=2;i<=num;i++){int u=ps[i];if(idm[u]!=sdm[u]){idm[u]=idm[idm[u]];}}
}
void build(){for(int i=2;i<=n;i++)G4[idm[i]].pb(i);
}
void dfs2(int u){sz[u]=1;for(auto v:G4[u])dfs2(v),sz[u]+=sz[v];
}
int main(){ios::sync_with_stdio(false);cin.tie(0),cout.tie(0);cin>>n>>m;for(int i=1;i<=m;i++){int x,y;cin>>x>>y;G[x].pb(y),G2[y].pb(x);}solve();build();dfs2(1);for(int i=1;i<=n;i++)cout<<sz[i]<<" ";
}

这篇关于【学习笔记】支配树基础理论的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



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

相关文章

Java深度学习库DJL实现Python的NumPy方式

《Java深度学习库DJL实现Python的NumPy方式》本文介绍了DJL库的背景和基本功能,包括NDArray的创建、数学运算、数据获取和设置等,同时,还展示了如何使用NDArray进行数据预处理... 目录1 NDArray 的背景介绍1.1 架构2 JavaDJL使用2.1 安装DJL2.2 基本操

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 个