Tarjan算法模板

一、最近公共祖先(LCA)

LCALeast Common Ancestor

P3379 【模板】最近公共祖先(LCA)

#include <bits/stdc++.h>

using namespace std;
typedef long long ll;

ll quickin(void)
{
	ll ret = 0;
	bool flag = false;
	char ch = getchar();
	while (ch < '0' || ch > '9')
	{
		if (ch == '-')    flag = true;
		ch = getchar();
	}
	while (ch >= '0' && ch <= '9' && ch != EOF)
	{
		ret = ret * 10 + ch - '0';
		ch = getchar();
	}
	if (flag)    ret = -ret;
	return ret;
}

// 存查询的数据结构 
typedef pair<int, int> P;  // first -- 另一个节点; second -- 查询编号 

const int MAX = 5e5 + 3;
int N, M, S;               // N -- 节点数; M -- 查询数; S -- 根节点 
vector<int> G[MAX];        // 存树,按无向图存储 
vector<P> query[MAX];      // 存查询,双向存 
int par[MAX], ans[MAX];    // par[] -- 各节点的父节点; ans[] -- 查询答案,按编号存储 
bool vis[MAX];             // vis[] -- 是否访问该节点 

// 并查集初始化 
void init(void)
{
	for (int i = 1; i <= N; ++i)
		par[i] = i;
}

// 并查集查询 
int find(int x)
{
	if (par[x] == x)    return x;
	else
		return par[x] = find(par[x]);
}

// tarjan算法 + 并查集 
void tarjan(int u)
{
	vis[u] = true;                         // 入u, 标记u
	
	// 遍历u的每条边 
	for (int i = 0; i < G[u].size(); ++i)
	{
		int v = G[u][i];
		if (!vis[v])                       // 防止访问父节点 
		{
			tarjan(v);
			par[v] = u;                    // 回u, v指向u 
		}
	}
	
	// 离u, 处理查询 
	for (int i = 0; i < query[u].size(); ++i)
	{
		P p = query[u][i];
		int v = p.first, id = p.second;
		if (vis[v])    ans[id] = find(v);      // 若v被访问过,则v的根节点即所求 
	}
}

int main()
{
	#ifdef LOCAL
	freopen("test.in", "r", stdin);
	#endif
	
	N = quickin(), M = quickin(), S = quickin();
	for (int i = 0; i < N - 1; ++i)
	{
		int a, b;
		a = quickin(), b = quickin();
		G[a].push_back(b);               // 双向存边 
		G[b].push_back(a);
	}
	for (int i = 0; i < M; ++i)
	{
		int a, b;
		a = quickin(), b = quickin();
		query[a].push_back(P(b, i));     // 双向存查询; i -- 查询编号 
		query[b].push_back(P(a, i));
	}
	
	init();
	tarjan(S);
	for (int i = 0; i < M; ++i)
		cout << ans[i] << endl;
	
	return 0;
}

二、强连通分量(SCC)

SCCStrongly Connected Component

B3609 [图论与代数结构 701] 强连通分量

1、基本概念

搜索树:对图深搜时,每个节点仅访问一次,节点按被访问的顺序和访问时经过的有向边组成搜索树
有向边的分类:

  • 树边:搜索树中的边
  • 返祖边:指向祖先节点的边
  • 横插边:右子树指向左子树的边
  • 前向边:指向子孙节点的边

定理1:返祖边与树边必定构成环,横插边可能与树边构成环,前向边无用。
定理2:强连通分量以树的形式存在于搜索树中,每个强连通分量都有一个根,其余节点都在根的子树中。

#include <bits/stdc++.h>

using namespace std;
typedef long long ll;

ll quickin(void)
{
	ll ret = 0;
	bool flag = false;
	char ch = getchar();
	while (ch < '0' || ch > '9')
	{
		if (ch == '-')    flag = true;
		ch = getchar();
	}
	while (ch >= '0' && ch <= '9' && ch != EOF)
	{
		ret = ret * 10 + ch - '0';
		ch = getchar();
	}
	if (flag)    ret = -ret;
	return ret;
}

const int MAX = 1e4 + 3;
int N, M;                       // N -- 节点数; M -- 边数 
vector<int> G[MAX];             // 存有向图 
int dfn[MAX], low[MAX], tot;    
/*
dfn[] -- 时间戳,各节点第一次被访问的顺序(也可以起到vis[]的作用) 
low[] -- 从该节点出发,能访问到的最早的时间戳
tot -- 更新时间戳 
*/
stack<int> S;                   // 将节点按时间戳压栈 
bool instk[MAX];                // 该节点是否在栈中 
vector<vector<int>> ans;        // 存储强连通分量 

void tarjan(int u)
{
	// 入u,盖戳,入栈 
	dfn[u] = low[u] = ++tot;
	S.push(u), instk[u] = true;
	
	// 遍历u的每条边 
	for (int i = 0; i < G[u].size(); ++i)
	{
		int v = G[u][i];
		if (!dfn[v])                       // 未访问过v(在搜索树中,v是u的孩子) 
		{
			tarjan(v);
			low[u] = min(low[u], low[v]);  // 回u,更新low 
		}
		else if (instk[v])                 // 访问过v,且在栈中(在搜索树中,v是u的祖先) 
		{
			low[u] = min(low[u], dfn[v]);
		}
	}
	
	// 离u,处理强连通分量 
	if (dfn[u] == low[u])
	{
		vector<int> scc;
		int t;
		do
		{
			t = S.top();
			S.pop(), instk[t] = false;
			scc.push_back(t);
		} while (t != u);
		
		sort(scc.begin(), scc.end());
		ans.push_back(scc);
	}
}

bool cmp(const vector<int> &a, const vector<int> &b)
{
	return a[0] < b[0];
}

int main()
{
	#ifdef LOCAL
	freopen("test.in", "r", stdin);
	#endif
	
	N = quickin(), M = quickin();
	for (int i = 0; i < M; ++i)
	{
		int a, b;
		a = quickin(), b = quickin();
		G[a].push_back(b);                  // 存储有向边 
	}
	
	// 图未必是连通的 
	for (int i = 1; i <= N; ++i)
	{
		if (!dfn[i])
			tarjan(i);
	}
	
	sort(ans.begin(), ans.end(), cmp);
	cout << ans.size() << endl;
	for (int i = 0; i < ans.size(); ++i)
	{
		for (int j = 0; j < ans[i].size(); ++j)
		{
			cout << ans[i][j] << ' ';
		}
		cout << endl;
	}
	
	return 0;
}

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

借势母亲节h5小游戏的作用是什么

企业商家往往喜欢借势节日开展营销&#xff0c;母亲节作为5月的重要节日自然不可错过&#xff0c;不同行业商家都有自己开展互动想要实现的效果&#xff0c;如品牌宣传曝光、引流及渠道跳转等。 基于微信社交属性&#xff0c;有利于品牌发展&#xff0c;在【雨科】平台拥有多款…

SparkSQL优化

SparkSQL优化 优化说明 缓存数据到内存 Spark SQL可以通过调用spark.sqlContext.cacheTable("tableName") 或者dataFrame.cache()&#xff0c;将表用一种柱状格式&#xff08; an inmemory columnar format&#xff09;缓存至内存中。然后Spark SQL在执行查询任务…

有什么方便实用的成人口语外教软件?6个软件教你快速进行口语练习

有什么方便实用的成人口语外教软件&#xff1f;6个软件教你快速进行口语练习 口语能力在语言学习中占据着重要的位置&#xff0c;因为它直接关系到我们与他人进行交流和沟通的效果。为了提高口语能力&#xff0c;很多成人选择通过外教软件进行口语练习&#xff0c;这些软件提供…

【强训笔记】day13

NO.1 代码实现&#xff1a; #include <iostream>#include<string>using namespace std;int n,k,t; string s;int func() {int ret0;for(int i0;i<n;i){char chs[i];if(chL) ret-1;else{if(i-1>0&&i-2>0&&s[i-1]W&&s[i-2]W) retk…

基于Springboot 的 Excel表格的导入导出

首先 &#xff0c;引入相关依赖EasyPOI <dependency><groupId>cn.afterturn</groupId><artifactId>easypoi-spring-boot-starter</artifactId><version>4.4.0</version></dependency> 编写实体类&#xff1a; Data AllArgs…

Java 框架安全:Struts2 漏洞序列测试.

什么是 Struts2 框架 Struts 2 是一个用于创建企业级 Java 应用程序的开源框架。它是一个 MVC&#xff08;模型-视图-控制器&#xff09;框架&#xff0c;用于开发基于 Java EE&#xff08;Java Platform, Enterprise Edition&#xff09;的 Web 应用程序。Struts 2 主要解决…

ROS机器人实用技术与常见问题解决

问题速查手册&#xff08;时实更新&#xff09;更加全面丰富的问题手册记录 1.机器人使用GPARTED挂载未分配空间 需要在图型界面下操作&#xff0c;建议使用no machine连接 安装gparted磁盘分区工具, sudo apt-get install gparted -y 启动软件 sudo gparted 点击磁盘/内存…

C# OpenCvSharp 图片找茬

C# OpenCvSharp 图片找茬 目录 效果 项目 代码 下载 效果 项目 代码 using OpenCvSharp; using System; using System.Diagnostics; using System.Drawing; using System.Windows.Forms; namespace OpenCvSharp_Demo { public partial class Form1 : Form { …

1688快速获取整店铺列表 采集接口php Python

在电子商务的浪潮中&#xff0c;1688平台作为中国领先的批发交易平台&#xff0c;为广大商家提供了一个展示和销售商品的广阔舞台&#xff1b;然而&#xff0c;要在众多店铺中脱颖而出&#xff0c;快速获取商品列表并进行有效营销是关键。 竞争对手分析 价格比较&#xff1a;…

mysql5.7数据库安装及性能测试

mysql5.7数据库安装及性能测试 记录Centos7.9下安装mysql 5.7并利用benchmark工具简单测试mysql的性能。 测试机&#xff1a;centos7.9 配置&#xff1a;4C8G40G 1. 下安装mysql5.7 安装mysql5.7&#xff1a; # 通过官方镜像源安装$ wget http://dev.mysql.com/get/mysql57-com…

pandas索引

pandas索引 一、索引1.1 建立索引1.2 重置索引1.3 索引类型1.4 索引的属性1.5 索引的操作 一、索引 1.1 建立索引 建立索引可以在数据读取加载中指定索引&#xff1a; import pandas as pd df pd.read_excel(team.xlsx, index_colname) # 将name列设置为索引 df.head()效…

C语言 函数的定义与调用

上文 C语言 函数概述 我们对函数进行了概述 本文 我们来说函数的定义和调用 C语言规定 使用函数之前&#xff0c;首先要对函数进行定义。 根据模块化程序设计思想&#xff0c;C语言的函数定义是互相平行、独立的&#xff0c;即函数定义不能嵌套 C语言函数定义 分为三种 有参函…

Kansformer?变形金刚来自过去的新敌人

​1.前言 多层感知器(MLPs),也被称为全连接前馈神经网络,是当今深度学习模型的基础组成部分。 MLPs在机器学习中扮演着至关重要的角色,因为它们是用于近似非线性函数的默认模型,这得益于通用近似定理所保证的表达能力。然而,MLPs真的是我们能构建的最佳非线性回归器吗?尽管ML…

鸿蒙OpenHarmony南向:【Hi3516标准系统入门(命令行方式)】

Hi3516标准系统入门&#xff08;命令行方式&#xff09; 注意&#xff1a; 从3.2版本起&#xff0c;标准系统不再针对Hi3516DV300进行适配验证&#xff0c;建议您使用RK3568进行标准系统的设备开发。 如您仍然需要使用Hi3516DV300进行标准系统相关开发操作&#xff0c;则可能会…

人工智能编程的创新探索 卧龙与凤雏的畅想

在一间宽敞明亮的办公室内&#xff0c;阳光透过窗户洒在地上&#xff0c;形成一片片光斑。卧龙和凤雏正坐在舒适的办公椅上休息&#xff0c;享受着这片刻的宁静。 卧龙微微皱眉&#xff0c;一只手托着下巴&#xff0c;略显苦恼地说道&#xff1a;“现在的人工智能&#xff0c;也…

vue2人力资源项目5组织架构的增删改查

编辑表单回显 父组件&#xff1a;这里用到了父亲调子组件的方法和同步异步先后方法的处理 //methods里else if (type edit) {this.showDialog true// 显示弹层this.currentNodeId id// 记录id&#xff0c;要用它获取数据// 在子组件中获取数据// 父组件调用子组件的方法来获…

【力扣】203、环形链表 II

142. 环形链表 II 要解决这道题&#xff0c;首先需要对问题进行拆解&#xff1a; 确定链表是否存在环确定环的入口点 如何判断是否存在环呢&#xff1f;这个比较容易想到&#xff0c;使用快慢指针即可判断链表是否存在环。我们定义两个指针&#xff1a; ListNode slow head…

Redis学习4——Redis应用之限流

引言 Redis作为一个内存数据库其读写速度非常快&#xff0c;并且支持原子操作&#xff0c;这使得它非常适合处理频繁的请求&#xff0c;一般情况下&#xff0c;我们会使用Redis作为缓存数据库&#xff0c;但处理做缓存数据库之外&#xff0c;Redis的应用还十分广泛&#xff0c…

远程服务器 docker XRDP 桌面访问 记录

需求描述: 我现在在远程连接 一台服务器&#xff0c;由于需要实验环境需要GUI 和 桌面系统&#xff0c;但是又想在 docker 中运行。因此&#xff0c;我现在首先需要通过 ssh 连接服务器&#xff0c;然后再服务器中连接 docker. REF: https://github.com/danielguerra69/ubuntu-…

代码随想录day19day20打卡

二叉树 1 二叉树的最大深度和最小深度 最大深度已经学习过了&#xff0c;实质就是递归的去判断左右子节点的深度&#xff0c;然后对其进行返回。 附加两个学习的部分&#xff1a; &#xff08;1&#xff09;使用前序遍历的方法求解 int result; void getdepth(TreeNode* nod…
最新文章