tarjan

Tarjan 【整理】

只谈情不闲聊 提交于 2019-12-04 02:00:05
Tarjan 【整理】 #include<bits/stdc++.h> using namespace std; class FastIO{ /* copyright (c) dgklr 2019. All rights reserved. */ bool if_debug = 0; char st[70]; // stack int pl; #ifdef linux #define putc(x) putchar_unlocked(x) #define getc() getchar_unlocked() #else #define putc(x) putchar(x) #define getc() getchar() #endif #define endl '\n' // I don't have the authority to get this. public: FastIO operator << (long long x){ pl = 0; if (x == 0) putc('0'); if (x < 0) putc('-'); while (x != 0) st[++pl] = x % 10 + 48, x /= 10; while (pl != 0) putc(st[pl]), pl --; return (*this); } FastIO operator <<

Tarjan模板

青春壹個敷衍的年華 提交于 2019-12-04 01:04:06
1.无向图求割点 例题: P3388 【模板】割点(割顶) #include<queue> #include<cstring> #include<cstdio> #include<algorithm> #include<cmath> #include<iostream> using namespace std; typedef long long ll; const int maxm=200007; int n,m,ans; int pre[maxm],last[maxm],other[maxm],l; bool ge[maxm]; int tot,dfn[maxm],low[maxm]; void add(int x,int y) { l++; pre[l]=last[x]; last[x]=l; other[l]=y; } void dfs(int x,int fa) { dfn[x]=low[x]=++tot; int child=0; for(int p=last[x];p;p=pre[p]) { int v=other[p]; if(!dfn[v]) { dfs(v,fa); low[x]=min(low[x],low[v]); if(dfn[x]<=low[v]&&x!=fa) ge[x]=1; if(x==fa) child++; } else low[x]=min

tarjan学习笔记

拜拜、爱过 提交于 2019-12-03 17:36:30
首先是求强连通分量: 这个的思路大致就是每个强连通分量为搜索树中的一棵子树。搜索时,把当前搜索树中未处理的节点加入一个堆栈,回溯时可以判断栈顶到栈中的节点是否为一个强连通分量。 定义DFN(u)为节点u搜索的次序编号(时间戳),Low(u)为u或u的子树能够追溯到的最早的栈中节点的次序号。 代码如下(伪): 1 void tarjan(int x) 2 { 3 dfn[x]=low[x]=++cnt; 4 instack[x]=1; 5 s.push(x); 6 int y; 7 for(int i=head[x];i;i=e[i].nxt) 8 { 9 y=e[i].to; 10 if(!dfn[y]) 11 { 12 tarjan(y); 13 low[x]=min(low[x],low[y]); 14 } 15 else if(instack[y]) low[x]=min(low[x],dfn[y]); 16 } 17 y=0; 18 if(dfn[x]==low[x]) 19 { 20 tot++; 21 while(x!=y) 22 { 23 y=s.top(); 24 s.pop(); 25 instack[y]=0; 26 belong[y]=tot; 27 } 28 } 29 } 30 void solve() 31 { 32 tot=cnt=0; 33

Tarjan专题

烂漫一生 提交于 2019-12-03 15:19:59
Tarjan专题 由于时间关系,本文只针对Tarjan做总结。如果有对Tarjan的入门有疑问请自行百度 有向图tarjan 在有向图中跑tarjan,通常都是求强连通分量(其中的所有点都可以间接直接到达)。一个点也算强连通。 设当前的节点为 \(u\) ,它的儿子节点为 \(v\) ,如果 \(v\) 没有被访问,那么时间戳戳一个, low[u]=min(low[u],low[v]) 。如果被访问过,那么 low[u]=min(low[u],dfn[v]) 。这里必须用一个栈来保存强连通及其大小。当一个点访问玩所有的儿子后,还有 dfn[u]==low[u] ,那么在这个栈里面的元素就都是强连通分量。因为我们dfs是是以树枝边进行遍历的。如果 \(u\) 能到达的最早的节点都只有它自己,那么它的儿子更没有机会遍历到前面的节点。输出强连通只需输出栈内元素即可。 缩点 求了强连通之后,将强连通变成一个点,那么整张图就变成了有向无环图。我们就可以在上面做一些拓扑序之类的问题了。 无向图tarjan 无向图有一些改变。边从有向变成了无向,任意两点只要连边就可以到达。所以在无向图上求强连通是没有意义的。 在无向图上一般求割点与桥。 顾名思义,干掉割点,其他的点就无法全部连通,干掉桥,其他的点也无法全部连通。见图: 对于割点,我们可以发现:存在 dfn[u]<=low[v] 。如果不存在

Tarjan板子

梦想的初衷 提交于 2019-12-03 09:58:15
缩点 inline void tarjan(int u){ dfn[u]=low[u]=++tarclock; vis[u]=1; s.push(u); for(int i=head[u];i!=-1;i=e[i].next){ int v=e[i].v; if(!dfn[v]){ tarjan(v); low[u]=min(low[u],low[v]); } else if(vis[v])low[u]=min(low[u],low[v]); } if(low[u]==dfn[u]){ sum++; while(1){ int x=s.top(); s.pop(); vis[x]=0; color[x]=sum; num[color[x]]++; if(x==u)break; } } } 割点 inline void tarjan(int u,int fa){ low[u]=dfn[u]=++time; int child=0; for(int i=head[u];i!=-1;i=e[i].next){ int v=e[i].v; if(!dfn[v]){ tarjan(v,fa); low[u]=min(low[u],low[v]); if(low[v]>=dfn[u]&&u!=fa)cut[u]=1; if(u==fa)child++; } low[u]=min(low[u]

tarjan复习笔记

最后都变了- 提交于 2019-12-03 09:28:16
tarjan复习笔记 (关于 tarjan 读法, 优雅一点读塔洋,接地气一点读塔尖 ) 0. 连通分量 有向图: 强连通分量(SCC)是个啥 就是一张图里面两个点能互相达到,那么这两个点在同一个强连通分量里, 极大强连通分量 就是最大的强连通分量。 无向图: 一个全部联通的子图就是一个连通分量。 其中用到tarjan暂时还有 边双连通分量 (e-DCC)和 点双连通分量 (v-DCC) 边双连通分量(e-DCC) 指的是一个子图中没有桥的话,这就是一个边双连通分量。 一个无向图的每一个极大边双连通子图称作此无向图的双连通分量。 点双连通分量(v-DCC) 对于一个无向图,如果一个点集,它内部的任意一个点对之间,至少有两条点完全不重复的路径,那么这个点集就是原图的一个点双连通分量。 无向图的双连通分量下面 待会复习 tarjan求强连通分量 这个就是所谓的tarjan强连通分量——缩点了。 对于一个单向联通的子图,我们从一个点出发会得到一个 搜索树 , 但是这个子图可不仅仅只有搜索树上的边。 (搜索树上的边下简称树边,非搜索树上的但是遇到的边下简称非树边) 按照搜索的顺序把点压到一个栈里。 如果当前我们找到一个非树边然后指向之前栈中的点里,那么从那个点到这个点之间都是强连通分量的一部分。 但是我们怎么找到一个最大的强连通分量呢? 我们设置一个搜索顺序 dfn[] 和追溯值 low[

$tarjan$简要学习笔记

半世苍凉 提交于 2019-12-03 09:14:46
$QwQ$因为$gql$的$tarjan$一直很差所以一直想着要写个学习笔记,,,咕了$inf$天之后终于还是写了嘻嘻. 首先说下几个重要数组的基本定义. $dfn$太简单了不说$QwQ$ 但是因为有向图无向图的$low$定义不一样,,,所以我我我我区分下两个$low$的定义,$QAQ$ 有向图中的$low[x]:$在栈中且$x$的子树能到达的点.的$dfn$最小值 无向图中的$low[x]:$能通过一条不在搜索树上的边与$x$的子树中的点联通的点.的$dfn$最小值. 首先了解下$tarjan$的核心代码趴$QwQ$ if(x是y搜索树上的父亲)low[x]=min(low[x],low[y]) else low[x]=min(low[x],dfn[y]) 不难理解?考虑$low_x$的定义是$x$及$x$的子树中能追溯到的$dfn$最小值.所以当$y$在$x$子树内时可以直接用$low$更新,否则就只能用$dfn$更新. 然后说下$tarjan$的几个基本应用 无向图割边 无向边$(x,y)$是桥,当且仅当搜索树上存在$x$的一个子节点$y$,满足$dfn[x]<low[y]$. 正确性显然不说. 注意因为这里的条件是小于号所以在更新$low[x]=min(low[x],dfn[y])$的时候要保证$y$不是$x$的父亲. 但是还有个要注意的在于如果有重边就不需要保证$y$不是

Tarjan算法之边双联通分量

隐身守侯 提交于 2019-12-03 07:48:11
定义 若一个无向连通图不存在割边,则称它为“边双连通图”。无向连通图的极大边双连通子图被称为“边双连通分量”,简记为“e-DCC” 定理 一个图为边双连通图,当且仅当任意一条边都至少包含在一个简单环中。 求法 把图中所有桥删除,剩下的都是e-DCC。 具体方法:一般用Tarjan标记所有桥边,再用dfs求出各连通块个数(遍历时不走桥)。 常和缩点搭配:把e-DCC的编号当做节点,桥当做节点间的连边,则会形成一棵树或一座森林。 例题 冗余路径 经典应用-构造边双连通分量:树的每一条边都是桥,但是给任意不同且不直接相连的两点加上一边后两点与其lca构成一个环,环上所有点为边强连通。由于题目要求连边最少,那么就使每次加的边让更多点边强连通。由上分析环的构造可知lca离两点越远对图上点贡献越多。那么每次将lca离两点最远的叶节点相连。本题不要求输出方案,所以因为每次都会 消掉两叶节点那么答案直接为(叶节点数 + 1)/2。(奇数剩余的一个点随便向其他点连边)。 #include<iostream> #include<cstdio> #include<cmath> #include<queue> #include<cstring> #include<algorithm> #define lson x<<1 #define rson x<<1|1 #define ll long long

缩点

独自空忆成欢 提交于 2019-12-03 06:31:38
老师讲图论-缩点-复习 我想 我没学过 缩点啊 \(OTL\) 先讲 割点 定义 在无向连通图中,如果将其中一个点以及所有连接该点的边去掉,图就不再连通,那么这个点就叫做割点 P3388 【模板】割点(割顶) 主要思想 观察 \(DFS\) 搜索树,我们可以发现有两类节点可以成为割点: 对根节点 \(u\) ,若其有两棵或两棵以上的子树,则该根结点u为割点; 对非叶子节点 \(u\) (非根节点),若其中的某棵子树的节点均没有指向u的祖先节点的回边,说明删除u之后,根结点与该棵子树的节点不再连通;则节点u为割点。 我们用 \(dfn[u]\) 记录节点u在DFS过程中被遍历到的次序号, \(low[u]\) 记录节点 \(u\) 或 \(u\) 的子树通过非父子边追溯到最早的祖先节点(即 \(DFS\) 次序号最小),那么 \(low[u]\) 的计算过程如下: #include <cstdio> #include <vector> #include <cstring> #include <iostream> #include <algorithm> using namespace std; #define reg register int #define isdigit(x) ('0' <= (x)&&(x) <= '9') template<typename T> inline

Tarjan算法之割边

你。 提交于 2019-12-03 05:15:40
定义 (在无向图中):在一个连通图中,如果删去其中一条边后,连通块的数量会增多,那么我们称这条边为桥或者是割边. 算法 tarjan,只需要判定low[v]>dfn[u]即可(u为父,v为子) 解释:如果子节点在不走原路情况下到不了父节点或父节点之前的点,那么子节点只能走原路回到父节点及之前节点,原路为必经之路,断掉就会产生新的个联通块,符合割边定义。 例题 HDU-4738 本题细节多多。 首先判断图是否联通,然后判断有无桥,判断桥时注意重边的干扰,最后输出桥的最小边权(如果是0应输出1,至少派一个人去吧) #include<iostream> #include<cstdio> #include<cmath> #include<queue> #include<cstring> #include<algorithm> #define lson x<<1 #define rson x<<1|1 #define ll long long #define rint register int #define mid ((st[x].l + st[x].r) >> 1) using namespace std; template <typename xxx> inline void read(xxx &x) { char c = getchar(),f = 1;x = 0; for(;c ^