Tarjan LCA
LCA的Tarjan算法的时间复杂度为O(n+q)是一种离线算法。
Tarjan求LCA的方法基于dfs与并查集
对于每一个点首先创建以本节点为父亲的并查集
然后分别访问子节点
返回时将子节点与当前结点合并
然后处理询问
对于每个节点u查找含有这个节点的询问
假设询问的点为v
看v是否被访问过
如果没有那么直接跳过等到遍历到 v 时直接可以找回来
如果遍历过 那么这个时候显然 LCA(u,v) == find( v )
举个例子(默认从左向右dfs遍历)
比如当前访问到11节点
发现询问中有(7,11)
这个时候7已经被访问过了而且fa值更新成了4
(因为这个时候还在遍历4的子树)
所以LCA(7,11)= 4
具体实现luogu LCA 3379:
const int maxn=500010<<1;
struct rec{int f,t,next,ans;
}e[maxn],ee[maxn];
int n=read(),m=read(),s=read(),p,now[maxn],fa[maxn],pp,head[maxn];
bool vis[maxn];
void add(int a,int b)
{p++;e[p].f=a;e[p].t=b;e[p].next=now[a];now[a]=p;
}
void addq(int a,int b)
{pp++;ee[pp].f=a;ee[pp].t=b;ee[pp].next=head[a];head[a]=pp;
}
int find(int x)
{return fa[x]==x ? x :fa[x]=find(fa[x]);
}
void tarjan(int x)
{fa[x]=x;vis[x]=1;for(int i=now[x];i;i=e[i].next){int v=e[i].t;if(!vis[v]) {tarjan(v);fa[find(v)]=x;}}for(int i=head[x];i;i=ee[i].next){int v=ee[i].t;if(vis[v]){int k=i-1;ee[k].ans=ee[k^1].ans=find(v);}}return;
}
int main()
{//ios::sync_with_stdio(false);for(int i=1;i<n;i++){int a=read(),b=read();add(a,b);add(b,a);}for(int i=1;i<=m;i++){int a=read(),b=read();addq(a,b);addq(b,a);}tarjan(s);for(int i=1;i<=pp;i+=2){cout<<ee[i].ans<<"\n";// cout<<ee[i].f<<" "<<ee[i].t<<endl;}return 0;
}
一些小细节:
- 读取询问的时候一定加双向边 保证能够在u访问不到v的情况下让v访问到u
- 加入询问边的时候可以在结构体里多开一个ans记录这次询问的结果
- 因为对于每次询问都记了两条编号相邻的边 因此当一次询问找到ans时要让
ee[i].ans=ee[(i-1)^1].ans=lca(u,v)
输出询问时就直接将编号每次+2就可以了 关于vis[ ]的位置:
LL发现他每次找到答案就cnt++
结果比输出结果要多
意识到如果lca(u,v)= u or v 时就会这样比如当前访问到7
有一个询问(7,4)
显然4已经被vis了 这个时候cnt++
然后遍历完子树返回到4的时候 又会有一个(4,7) cnt又++
类似的情况都因为vis在遍历子树之前就被标记了
所以
只要把vis放到第一个for循环后边
然后函数参数里边记一个father防止去掉vis后儿子访问父亲
就可以保证每次询问只被更新一次所以呢
还是用我一开始的存答案方法比较省事儿哈哈哈哈哈哈哈
Tarjan LCA相关推荐
- P5236-[模板]静态仙人掌【tarjan,LCA】
正题 题目链接:https://www.luogu.com.cn/problem/P5236 题目大意 给一个边仙人掌(一条边至多在一个环中),每次询问两点之间的距离 解题思路 我们对于每个环新建方点 ...
- ssl1746-商务旅行【tarjan,LCA】
正题 题目大意 一个n-1个点的有向无环图,给出若干个点,要求依次到达的最少时间. 解题思路 有向无环图我们可以把其看做一颗树,然后每次用LCA求两个点之间的距离,然后把所有距离统计一下就是结果. 代 ...
- POJ1330-Nearest Common Ancestors【tarjan,LCA】
正题 题目链接: http://poj.org/problem?id=1330 题目大意 就是给出一棵树,求LCA(最近公共祖先) 解题思路 用tarjan求LCA,这里给出tarjan算法 代码 # ...
- POJ 3694 Network(tarjan+lca+并查集)
题目 给定一张NNN个点MMM条边的无向连通图,然后执行QQQ次操作,每次向图中添加一条边,并且询问当前无向图中"桥"的数量. 题解 先求出图中所有的边双,然后缩点 令c[x],c ...
- 浅谈LCA问题(最近公共祖先)(三种做法)
[模板]最近公共祖先(LCA) 题目描述 如题,给定一棵有根多叉树,请求出指定两个点直接最近的公共祖先. 输入格式 第一行包含三个正整数 N,M,SN,M,SN,M,S,分别表示树的结点个数.询问的个 ...
- 2017.7.26 幻想乡战略游戏 失败总结
因为时间关系,就先强行明白了 dt点分治是接触过最难懂的东西了(可能是这一个题) 就是建立一颗点分树 注意子树向重心连边,修改时直接往上跳,用过点和不过点可以简单容斥 就知道这些了 码: #inclu ...
- SDOI 2017R2游记
今年已经没有希望了,纯粹的来见见题涨涨见识. day0 晚上到宾馆,还是非常的熟悉的地方,只是少了一个月前的紧张. 千万不要作死吃特辣黄焖鸡,肠胃会非常难受. day1 早上7:30到师大附中,路上人 ...
- NOIP2018赛前停课集训记——最后的刷板子计划
前言 再过两天就\(NOIP2018\)了. 于是,我决定不做其他题目,开始一心一意刷板子了. 这篇博客记录的就是我的刷板子计划. [洛谷3383][模板]线性筛素数 这种普及-的题目我还写挂了两次( ...
- NOIP2017模拟赛(4) 总结
前言:本次考试第二题炸了,删了暴力,后果很惨... a 约数 题目描述 设K是一个正整数,设X是K的约数,且X不等于1也不等于K. 加了X后,K的值就变大了,你可以重复上面的步骤.例如K= 4,我们可 ...
最新文章
- Yolo:实时目标检测实战(下)
- 谈谈职业规划——CSDN对我的采访
- 如何在Jupyter notebook中运行python的.py文件,以及ipynb文件与py文件的相互转化
- 机器人能翻转汉堡肉饼 短暂上岗后将“休息”四天
- 【招聘(广州)】 招聘.NET程序员
- RDLC系列之五 初试XAML
- Referenced file contains errors (http://www.zeroturnaround.com/alderaan/rebel-2_0.xsd).
- python训练营微信广告发送机_python实现给微信公众号发送消息的方法
- 让go语言调用外部程序时支持管道符
- ios开发笔记之 emoji表情字符编码集合
- OpenCV图像模糊处理
- 格兰因果模型可以分析哪些东西_论文实证经验分享|VAR模型实操步骤(上)
- 认证杯网络挑战赛C题破局共享汽车
- 两岸四地消费者信心指数出炉:中国大陆消费者信心指数评析
- BZOJ 2006超级钢琴
- 深入理解计算机大端与小端
- Java 内存分区之什么是 CCS区 Compressed Class Space 类压缩空间
- PPPOE总结和配置
- 曲线救国--为Chrome安装Edge浏览器插件
- 定了!2022京东全球科技探索者大会之京东云峰会7月13日北京见