当前位置:网站首页>最近公共祖先离线做法(tarjan)
最近公共祖先离线做法(tarjan)
2022-07-01 19:36:00 【Zqchang】
在线离线
在线和离线一般是针对有询问的题目
在线做法:就是每读入一个询问,就可以立即算一个答案,然后输出
离线做法:我们必须先把所有询问统一读进来,然后统一计算完之后,再把所有询问统一输出
tarjan O(n + m)
n是节点数量,m是询问数量
本质是对向上标记法的优化
向上标记法
具体可看上一个在线做法
在深度优先遍历过程中把所有点分为三大类
1.已经遍历过,且回溯过的点,被搜过,而且子树被搜完
2.正在搜索的分支
3.还未搜索到的点
假设是从左往右搜索,就形成了这样的一棵树绿色是第一种,红色是第二种,也就是一个路径,其他的是第三种

对于正在搜索的点,我们找一下与之相关的询问,由上图可以发现,当前询问的点x和绿色部分的公共祖先都是路径总的点,因为可以将路径中点的子树合并到该点中去,最后求公共祖先的时候,就是看一下那个点被合并到哪个点去了,可以用并查集来实现,这就是找祖宗节点
这样,每个点只会被遍历一次,也只会被合并一次,对于每个查询也只会查询一次
主要思想
我们在遍历当前这个分支的时候,对于所有和这个点相关的节点的公共祖先,我们可以发现,如果这个点已经被遍历过了的话,所在整个子树的公共祖先都是路径中的那个点,也就是该子树的根节点,也就是每次遍历完一个点之后,就可以把当前这个点直接合并到根节点当中去,当我们查询的时候,就可以直接在并查集里面查当前元素的代表元素是谁,这个代表元素就是它的公共祖先
这个要注意什么时候合并,就是要在回溯完之后,再把它合并到父节点中
例题
距离
题意就是要求两个点之间的距离
方法如图,都算出来到根节点的距离,再减去两倍的公共祖先的距离
#include<bits/stdc++.h>
using namespace std;
#define endl '\n'
#define int long long
#define PII pair<int, int>
const int N = 1e4 + 10;
#define x first
#define y second
vector<PII> v[N];
int n, m, a, b, k;
int dist[N];//存储每个点到根节点距离
int p[N];
int res[N * 2];// 存答案
int st[N];
vector<PII> query[N]; // first存查询的另外一个点,second存查询编号
int find(int x)
{
if (p[x] != x) p[x] = find(p[x]);
return p[x];
}
void dfs(int u, int fa)
{
for(auto i : v[u])
{
if(i.x == fa) continue;
dist[i.x] = dist[u] + i.y;
dfs(i.x, u);
}
}
void tarjan(int u)
{
st[u] = 1;
for(auto i : v[u])
{
if(!st[i.x])
{
tarjan(i.x);
p[i.x] = u;
}
}
for(auto i : query[u])
{
if(st[i.x] == 2)//查看另一个点是不是回溯过了,如果没回溯过就跳
{
int anc = find(i.x);
res[i.y] = dist[u] + dist[i.x] - dist[anc] * 2;
}
}
st[u] = 2;
}
signed main()
{
cin >> n >> m;
for(int i=1; i<=n-1; i++)
{
cin >> a >> b >> k;
v[a].push_back({
b, k});
v[b].push_back({
a, k});
}
for(int i=1; i<=m; i++)
{
cin >> a >> b;
if(a != b)
{
query[a].push_back({
b, i});
query[b].push_back({
a, i});
}
}
for(int i=1; i<=n; i++) p[i] = i;
dfs(1, -1);
tarjan(1);
for(int i=1; i<=m; i++) cout << res[i] << endl;
return 0;
}
边栏推荐
- 强大的万年历微信小程序源码-支持多做流量主模式
- EURA欧瑞E1000系列变频器使用PID实现恒压供水功能的相关参数设置及接线
- cocoaPods 添加成功后,导入不了头文件或者not found file 报错
- 喜马拉雅自研网关架构演进过程
- Richview trvdocparameters page parameter settings
- 牛客编程题--必刷101之字符串(高效刷题,举一反三)
- 【let var const】
- 8K HDR!| Hevc hard solution for chromium - principle / Measurement Guide
- RichView 文档中的 ITEM
- 图片拼图微信小程序源码_支持多模板制作和流量主
猜你喜欢

深度学习 神经网络基础

How to create a pyramid with openmesh

以飞地园区为样本,看雨花与韶山如何奏响长株潭一体化发展高歌

Importance of EDA tools to chip industry knowledge popularization

RichView 文档中的 ITEM

2022熔化焊接与热切割上岗证题目模拟考试平台操作

2022安全员-B证考试练习题模拟考试平台操作

2022安全员-A证考题及在线模拟考试

Niuke programming question -- must brush the string of 101 (brush the question efficiently, draw inferences from one instance)

2022年低压电工考试试题及答案
随机推荐
After adding cocoapods successfully, the header file cannot be imported or an error is reported in not found file
Kuberntes云原生实战一 高可用部署架构
从20s优化到500ms,我用了这三招
Halcon知识:三维重构的一个尝试
[C language] explain the usage of memset() function in detail
Error in installing sharp
利用QEventLoop实现同步等待槽函数返回
Test of NSI script
Is it safe to open an account online? Can a novice open a stock trading account.
There are four ways to write switch, you know
Internship: gradually moving towards project development
MySQL数据库驱动(JDBC Driver)jar包下载
Items in richview documents
Develop those things: easycvr platform adds playback address authentication function
leetcode刷题:栈与队列04(删除字符串中的所有相邻重复项)
喜马拉雅自研网关架构演进过程
[multithreading] realize the singleton mode (hungry and lazy) realize the thread safe singleton mode (double validation lock)
RichView RichEdit SRichViewEdit PageSize 页面设置与同步
What did you learn about cheating after you went to college?
人脸识别系统 —— OpenCV人脸检测