连通性相关

强联通分量

强连通:有向图 \(G\) 强连通表示,\(G\) 中任意两个结点连通。

强连通分量( Strongly Connected Components ,简称 \(\operatorname{SCC}\) ):极大的 强连通子图。

Tarjan

维护了以下两个变量:

  • \(dfn\) :深度优先搜索遍历时结点 \(u\) 被搜索的次序 。

  • \(low\) :设以 \(u\) 为根的子树为 \(subtree(u)\)\(low\) 定义为以下结点的 \(dfn\) 的最小值: \(subtree(u)\) 中的结点;从 \(subtree(u)\) 通过 一条 不在搜索树上的边能到达的结点 。

从根开始的一条路径上的 \(dfn\) 严格递增,\(low\) 严格非降。

对于一个连通分量图,我们很容易想到,在该连通图中有且仅有一个 \(dfn[u]=low[u]\) 。该结点一定是在深度遍历的过程中,该连通分量中第一个被访问过的结点,因为它的 \(dfn\) 值和 \(low\) 值最小,不会被该连通分量中的其他结点所影响。

因此,在回溯的过程中,判定 \(dfn[u]=low[u]\) 的条件是否成立,如果成立,则栈中从 后面的结点构成一个 \(\operatorname{SCC}\)

P2341 [HAOI2006]受欢迎的牛 G \(-\) 模板

$\texttt{code}$
#define Maxn 10005
#define Maxm 50005
void tarjan(int u)
{dfn[u]=low[u]=++Time; s.push(u),ins[u]=true;for(int i=hea[u];i;i=nex[i]){if(!dfn[ver[i]]) tarjan(ver[i]),low[u]=min(low[ver[i]],low[u]);else if(ins[ver[i]]) low[u]=min(dfn[ver[i]],low[u]);}if(dfn[u]==low[u]){sum+=1;do{belong[u]=sum;u=s.top(); s.pop(); ins[u]=false;cnt[sum]+=1;} while(dfn[u]!=low[u]);}
}for(int i=1;i<=n;i++) if(!dfn[i]) tarjan(i);

时间复杂度 \(O(n+m)\)

Kosaraju

复杂度 \(O(n+m)\)

Garbow

复杂度 \(O(n+m)\)

我们可以利用强联通分量将一张图的每个强连通分量都缩成一个点。

然后这张图会变成一个 \(\operatorname{DAG}\),可以进行拓扑排序以及更多其他操作 。

应用 \(-\) 缩点

P3387 【模板】缩点

for(int i=1;i<=n;i++) if(!dfn[i]) tarjan(i);
for(int i=1;i<=tot[0];i++)if(belong[fro[0][i]]!=belong[ver[0][i]])add(1,belong[fro[0][i]],belong[ver[0][i]]),ind[belong[ver[0][i]]]++;
topo();

割点与桥

在无向图中删去这个点 \(/\) 边会使极大强联通增大,那么这个点 \(/\) 边为割点 \(/\) 桥 。

注意这里的 \(dfn\) 表示不经过父亲,能到达的最小的 \(dfn\)

割点

P3388 【模板】割点(割顶)

关键条件:

  • \(u\) 是根节点,当至少存在 \(2\) 条边满足 \(low[v] >= dfn[u]\)\(u\) 是割点 。

  • \(u\) 不是根节点,当至少存在 \(1\) 条边满足 \(low[v] >= dfn[u]\)\(u\) 是割点 。

$\texttt{code}$
void tarjan(int u,int fa)
{dfn[u]=low[u]=++Time;for(int i=hea[u];i;i=nex[i]){if(!dfn[ver[i]]){tarjan(ver[i],u),low[u]=min(low[ver[i]],low[u]);if(low[ver[i]]>=dfn[u]) cnt[u]+=1;}else if(ver[i]!=fa) low[u]=min(dfn[ver[i]],low[u]);}
}for(int i=1;i<=n;i++) if(!dfn[i]) cnt[i]-=1,tarjan(i,0);
for(int i=1;i<=n;i++) if(cnt[i]>=1) ans+=1;

割边(桥)

关键条件:

  • 当存在一条边条边满足 \(low[v] > dfn[u]\) 则边 \(i\) 是割边

关键部分的代码:

注意:记录上一个访问的边时要记录边的编号,不能记录上一个过来的节点(因为会有重边)!!!

$\texttt{code}$
void tarjan(int x,int Last_edg)
{dfn[x]=low[x]=++Time;for(int i=hea[x];i;i=nex[i]){if(!dfn[ver[i]]){tarjan(ver[i],i);low[x]=min(low[x],low[ver[i]]);if(low[ver[i]]>dfn[x]) edg[i]=edg[i^1]=1;}else if(i!=(Last_edg^1)) low[x]=min(low[x],dfn[ver[i]]);}
}for(int i=1;i<=n;i++) if(!dfn[i]) tarjan(i,0);
for(int j=2;j<=tot;j+=2) ans+=tag[j];

双联通分量

边双联通分量

显然,找出每一个桥,去掉这些桥之后的每一个联通块都是一个边双联通字图。

注意:用边双缩点的时候先处理出割边,之后用 \(\text{dfs}\) 求出每一个双联通分量,不用栈!!

例题:P2860 [USACO06JAN]Redundant Paths G

$\texttt{solution}$

一句话题意:要将原图转化为边双联通图需要添加的最少边数

我们可以先将所有的桥找出来,并同时对所有边双缩点,会得到一颗缩完点的、由桥构成的“树”。

我们发现这棵“树”上“叶子结点”的个数除二向上取整就是需要添加的边的条数。

点双连通分量

小粉兔的圆方树——点双详解

【模板】点双连通分量

回忆 \(low\) 的定义,就是 \(x\) 的子树内最多经过一条反祖边或一条向父亲的边能够到达的最小的 \(dfn\) 值。

\(x\) 不是这个连通块的根时,如果存在一条边满足 \(low(ver)\ge dfn(x)\),那么 \(x\) 就是一个个点。

\(x\) 是根时,\(x\) 需要存在至少两条边满足以上条件。

这是因为当 \(x\) 为根时,没有父亲与之相连。

那么当我们在求点双时,只需要判断子树内的 \(low\) 是否会 \(<dfn(x)\),若会,则说明子树中的点能够到达 \(x\) 的祖先,\(x\) 必然不是个点。而若不会,即 \(low(ver)\ge dfn(x)\),则说明 \(x\) 是这个点双的顶端个点,这时可以将递归进入的点都弹出,直至栈顶元素变为 \(ver\),再将 \(ver\) 从栈中弹出,加上 \(x\) 就是这个点双联通分量了。

还要注意孤立点的情况。

如果需要处理点双中点的个数,那么可以在栈中存放点,例如一下代码:

void tarjan(int x)
{dfn[x]=low[x]=++Time,sta[++tp]=x;if(tp==1 && !hea[x]) { SCC[++sum].pb(x); return; }for(int i=hea[x];i;i=nex[i]){if(!dfn[ver[i]]){tarjan(ver[i]);low[x]=min(low[x],low[ver[i]]);if(low[ver[i]]>=dfn[x]){sum++;do { SCC[sum].pb(sta[tp--]); }while(sta[tp+1]!=ver[i]);SCC[sum].pb(x);}}else low[x]=min(low[x],dfn[ver[i]]);}
}

而如果需要处理点双中的边,那么就需要在栈中存边,如以下代码:

void tarjan(int x,int fa)
{dfn[x]=low[x]=++Time;int cntson=0;for(int i=hea[x];i;i=nex[i]){if(!dfn[ver[i]]){sta[++tp]=i,tarjan(ver[i],i),cntson++;low[x]=min(low[x],low[ver[i]]);if(low[ver[i]]>=dfn[x]){isdian[x]=true,sum++;int tmp=0;do{tmp=sta[tp--];scc[sum].pb(fro[tmp]);scc[sum].pb(ver[tmp]);}while(tmp!=i);}}else if(i!=(fa^1)) low[x]=min(low[x],dfn[ver[i]]); }if(fa==0 && cntson==1) isdian[x]=false;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/318191.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

CF505E-Mr. Kitayuta vs. Bamboos【贪心,二分】

正题 题目链接:https://www.luogu.com.cn/problem/CF505E 题目大意 开始一个长度为nnn的序列hhh&#xff0c;mmm天每天你可以kkk次选择一个hih_ihi​让它等于himax{hi−p,0}h_imax\{h_i-p,0\}hi​max{hi​−p,0}&#xff0c;然后结束时让每个hihiaih_ih_ia_ihi​hi​ai​&…

阶段总结:8.09-8.18 十日模拟

一图流了解一下 文章目录十日谈总结十日谈 再总结一下 8.09 搜索模拟&#xff1a;25分。…毕竟是第一天不太适应吧 &#xff08;拼命找借口&#xff09;。没有看到标题就很淦&#xff0c;就是全写挂了而已&#xff0c;已经无从谈起…hzwer的粉丝那题提醒我们不要被吓人的数据…

学习有向图和无向图的强连通分量(基本概念+割点+点双联通分量+桥+边双连通分量+全套模板【Tarjan】)

最近总是考到Tarjan&#xff0c;让我措手不及基本概念割点以及点双连通分量Tarjan法求割点推导过程代码实现Tarjan法求点双连通分量推导过程代码实现有向图的Tarjan缩点桥与边双连通分量Tarjan法求桥理论推导代码实现Tarjan法求边双连通分量理论推导代码实现前言&#xff1a;有…

.NET Core下的Spring Cloud——前言和概述

前言前几年一直在写类似dubbo&#xff0c;Spring Cloud的微服务框架辗辗转转重复了多次&#xff0c;也重构推翻了很多次&#xff0c;其中诞生了“Rabbit.Rpc”,”Go”,”RabbitCloud”等开源项目。其中不乏他人对这些项目的完善。很高兴自己的开源项目能够给他人提供思路和复用…

期望 概率DP

期望 \(x\) 的期望 \(E(x)\) 表示平均情况下 \(x\) 的值。 令 \(C\) 表示常数&#xff0c; \(X\) 和 \(Y\) 表示两个随机变量。 \(E(C)C\) \(E(C \times X)C \times E(X)\) \(E(XY)E(X)E(Y)\) 期望的线性性 \(E(XY)\) 不一定等于 \(E(X) \times E(Y)\) 期望练习&#xff1a…

CF785E Anton and Permutation

CF785E Anton and Permutation 题意&#xff1a; 对于一个长度为 n 的序列进行 k 次操作&#xff0c;每次操作都是交换序列中的某两个数。对于每一个操作&#xff0c;回答当前序列中有多少个逆序对。 1<n<200000 1<q<50000 题解&#xff1a; 动态逆序对&#x…

P5311-[Ynoi2011]成都七中【点分树,树状数组】

正题 题目链接:https://www.luogu.com.cn/problem/P5311 题目大意 给出nnn个点的一棵树&#xff0c;每个节点有一个颜色&#xff0c;mmm次询问提出区间[l,r][l,r][l,r]的点构成的生成子图中xxx所在连通块的颜色数。 1≤n,m,ai≤1051\leq n,m,a_i\leq 10^51≤n,m,ai​≤105 解…

[ NOIP提高组 2016]愤怒的小鸟(暴搜 + 状压DP)// [SNOI2017]一个简单的询问(莫队)

一次性写两道题T1&#xff1a;一个简单的询问题目题解代码实现T2&#xff1a;愤怒的小鸟题目暴搜题解暴搜代码实现状压DP题解状压DP代码实现T1&#xff1a;一个简单的询问 题目 给你一个长度为 N 的序列 ai ,1≤i≤N&#xff0c;和 q 组询问&#xff0c;每组询问读入 l1,r1,l…

微软发布新的 Azure Pipelines 功能和集成

在最近举行的Connect()大会上&#xff0c;微软发布了几项新功能以及与 Azure Pipelines 的集成&#xff0c;包括 Visual Studio Code 的 Azure Pipelines 扩展、GitHub 版本管理、对 IoT 项目的支持以及 ServiceNow 集成。自从 9 月份推出 Azure Pipelines 以来&#xff0c;这种…

平衡树练习总结

文章目录前言普通平衡树文艺平衡树郁闷的出纳员书架宠物收养场机械排序千山鸟飞绝总结前言 专门刷了一天半的平衡树 &#xff08;附带划水OvO&#xff09; 使用的是蜜汁常数的splay 感觉对平衡树的理解还是有帮助的 一些较为常规的平衡树的题应该是差不多了 更正之前刚学的观点…

二维树状数组

二维树状数组可以实现在平面上的区域加、区域查询等操作。 区域修改 我们在一维时维护树状数组的区间操作时&#xff0c;对其进行了差分。类比一维的思想&#xff0c;我们在二维平面上也对树状数组差分。 我们来看二维的前缀和&#xff1a; \[sum(i,j)sum(i-1,j)sum(i,j-1)-sum…

【AcWing 249. 蒲公英】

【AcWing 249. 蒲公英】 题意&#xff1a; 长度为n的序列&#xff0c;给定区间&#xff0c;求区间众数&#xff0c;如果出现次数相同&#xff0c;输出编号最小的 题解&#xff1a; 区间众数&#xff0c;不带修改&#xff0c;强制在线&#xff08;否则可以莫队&#xff09; …

年末展望:Oracle 对 JDK收费和.NET Core 给我们的机遇

2018年就结束了&#xff0c;马上就要迎来2019年&#xff0c;这一年很不平凡&#xff0c;中美贸易战还在继续&#xff0c;IT互联网发生急剧变化&#xff0c;大量互联网公司开始裁员&#xff0c;微软的市值在不断上升 &#xff0c;在互联网公司的市值下跌过程中爬到了第一的位置&…

等比数列三角形 (数论 + 黄金分割点)+ JOISC 2016 Day3 T3 「电报」(基环树 + 拓扑排序)

文章目录T1&#xff1a;等比数列三角形题目题解代码实现T2&#xff1a;电报题目题解代码实现T1&#xff1a;等比数列三角形 题目 求三边都是 ≤n 的整数&#xff0c;且成等比数列的三角形个数 注意三角形面积不能为 0 注意 oeis 中未收录此数列&#xff0c;所以并不需要去搜了…

模板:笛卡尔树

介绍 笛卡尔树是一种非常特殊的二叉搜索树。每个节点有两个信息x和y。如果只考虑 x&#xff0c;它是一棵二叉搜索树&#xff0c;如果只考虑 y&#xff0c;它是一个小根堆。 实现 按照y升序插入 显然应该插入到一条极右链上 但为了维护x二叉搜索树的性质 对于右链上x>当前…

乱搞

占个坑&#xff0c;找时间补

【AcWing 243. 一个简单的整数问题2】

例题&#xff1a;【AcWing 243. 一个简单的整数问题2】 线段树模板题&#xff0c;区间修改区间求和。 题解&#xff1a; 将序列分成N/B块&#xff0c;维护&#xff1a; id[i] i/B&#xff0c;i所在块标号 res[id] 第id块的sum base[id] 第id块的add标记修改时&#xff0…

CF1540B-Tree Array【数学期望,dp】

正题 题目链接:https://www.luogu.com.cn/problem/CF1540B 题目大意 nnn个点的一棵树&#xff0c;开始随机选择一个点标记&#xff0c;然后每次随机选择一个与被标记点连边的点标记&#xff0c;按照标记顺序排列&#xff0c;求期望逆序对数。 1≤n≤2001\leq n\leq 2001≤n≤2…

使用PerfView监测.NET程序性能(三):分组

在上一篇博客使用PerfView监测.NET程序性能&#xff08;二&#xff09;&#xff1a;Perfview的使用中&#xff0c;我们通过Perfview帮助文件中自带的代码来简单使用了Perfview&#xff0c;了解了基本操作。现在来看看Perfview中的分组操作&#xff08;Grouping&#xff09;。分…

【做题记录】构造题

CF468C Hack it! 题意&#xff1a; 令 \(F(x)\) 表示 \(x\) 的各个位上的数字之和&#xff0c;如 \(F(1234)123410\) 。 给定 \(a(a\le 10^{18})\) &#xff0c;请求出任意一组 \(l,r(l,r\le 10^{200})\) &#xff0c;要求满足&#xff1a; \[\sum_{il}^{r}F(i)\pmod{a}0 \]输出…