Tarjan LCA
程序员文章站
2022-05-15 14:02:16
...
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后儿子访问父亲
就可以保证每次询问只被更新一次所以呢
还是用我一开始的存答案方法比较省事儿哈哈哈哈哈哈哈
下一篇: BZOJ2438 杀人游戏
推荐阅读
-
图论算法----Tarjan求无向图双连通分量及拓展
-
tarjan算法求解强连通分量
-
tarjan算法求强连通分量详解(避免误区)
-
不一样的LCA——luoguP1852跳跳棋
-
洛谷P1600 天天爱跑步(差分 LCA 桶)
-
BZOJ2208: [Jsoi2010]连通数(tarjan bitset floyd)
-
BZOJ1093: [ZJOI2007]最大半连通子图(tarjan dp)
-
洛谷 P3388 【模板】割点(割顶)(Tarjan)
-
2020暑期牛客多校训练营第九场(K)The Flee Plan of Groundhog(lca,树形dp)
-
[HDU-1269] SCC tarjan求强连通分量模板题