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相关推荐

  1. P5236-[模板]静态仙人掌【tarjan,LCA】

    正题 题目链接:https://www.luogu.com.cn/problem/P5236 题目大意 给一个边仙人掌(一条边至多在一个环中),每次询问两点之间的距离 解题思路 我们对于每个环新建方点 ...

  2. ssl1746-商务旅行【tarjan,LCA】

    正题 题目大意 一个n-1个点的有向无环图,给出若干个点,要求依次到达的最少时间. 解题思路 有向无环图我们可以把其看做一颗树,然后每次用LCA求两个点之间的距离,然后把所有距离统计一下就是结果. 代 ...

  3. POJ1330-Nearest Common Ancestors【tarjan,LCA】

    正题 题目链接: http://poj.org/problem?id=1330 题目大意 就是给出一棵树,求LCA(最近公共祖先) 解题思路 用tarjan求LCA,这里给出tarjan算法 代码 # ...

  4. POJ 3694 Network(tarjan+lca+并查集)

    题目 给定一张NNN个点MMM条边的无向连通图,然后执行QQQ次操作,每次向图中添加一条边,并且询问当前无向图中"桥"的数量. 题解 先求出图中所有的边双,然后缩点 令c[x],c ...

  5. 浅谈LCA问题(最近公共祖先)(三种做法)

    [模板]最近公共祖先(LCA) 题目描述 如题,给定一棵有根多叉树,请求出指定两个点直接最近的公共祖先. 输入格式 第一行包含三个正整数 N,M,SN,M,SN,M,S,分别表示树的结点个数.询问的个 ...

  6. 2017.7.26 幻想乡战略游戏 失败总结

    因为时间关系,就先强行明白了 dt点分治是接触过最难懂的东西了(可能是这一个题) 就是建立一颗点分树 注意子树向重心连边,修改时直接往上跳,用过点和不过点可以简单容斥 就知道这些了 码: #inclu ...

  7. SDOI 2017R2游记

    今年已经没有希望了,纯粹的来见见题涨涨见识. day0 晚上到宾馆,还是非常的熟悉的地方,只是少了一个月前的紧张. 千万不要作死吃特辣黄焖鸡,肠胃会非常难受. day1 早上7:30到师大附中,路上人 ...

  8. NOIP2018赛前停课集训记——最后的刷板子计划

    前言 再过两天就\(NOIP2018\)了. 于是,我决定不做其他题目,开始一心一意刷板子了. 这篇博客记录的就是我的刷板子计划. [洛谷3383][模板]线性筛素数 这种普及-的题目我还写挂了两次( ...

  9. NOIP2017模拟赛(4) 总结

    前言:本次考试第二题炸了,删了暴力,后果很惨... a 约数 题目描述 设K是一个正整数,设X是K的约数,且X不等于1也不等于K. 加了X后,K的值就变大了,你可以重复上面的步骤.例如K= 4,我们可 ...

最新文章

  1. Yolo:实时目标检测实战(下)
  2. 谈谈职业规划——CSDN对我的采访
  3. 如何在Jupyter notebook中运行python的.py文件,以及ipynb文件与py文件的相互转化
  4. 机器人能翻转汉堡肉饼 短暂上岗后将“休息”四天
  5. 【招聘(广州)】 招聘.NET程序员
  6. RDLC系列之五 初试XAML
  7. Referenced file contains errors (http://www.zeroturnaround.com/alderaan/rebel-2_0.xsd).
  8. python训练营微信广告发送机_python实现给微信公众号发送消息的方法
  9. 让go语言调用外部程序时支持管道符
  10. ios开发笔记之 emoji表情字符编码集合
  11. OpenCV图像模糊处理
  12. 格兰因果模型可以分析哪些东西_论文实证经验分享|VAR模型实操步骤(上)
  13. 认证杯网络挑战赛C题破局共享汽车
  14. 两岸四地消费者信心指数出炉:中国大陆消费者信心指数评析
  15. BZOJ 2006超级钢琴
  16. 深入理解计算机大端与小端
  17. Java 内存分区之什么是 CCS区 Compressed Class Space 类压缩空间
  18. PPPOE总结和配置
  19. 曲线救国--为Chrome安装Edge浏览器插件
  20. 定了!2022京东全球科技探索者大会之京东云峰会7月13日北京见

热门文章

  1. 女人把自己打扮得很漂亮,是给谁看的?
  2. 白鹭安装node_在白鹭引擎中使用NodePlayer.js开发直播视频游戏
  3. 【数据结构】停车场问题(代码有少量问题,正在修改,故计2天)
  4. 2.特定领域知识图谱融合方案:文本匹配算法(Simnet、Simcse、Diffcse)【二】
  5. 面向程序员的数据挖掘指南-----第三章:隐式评价和基于物品的过滤算法
  6. 《如何阅读一本书》读书心得
  7. awk学习,从入门到实战
  8. 锐捷EG系列路由器WEB界面ipsec设置说明
  9. 云电脑用虚拟键盘可以玩cf吗
  10. 运行C程序的步骤和方法