tarjan,树剖,倍增求lca

1.tarjan求lca

 Tarjan(u)//marge和find为并查集合并函数和查找函数
{
        for each(u,v)    //访问所有u子节点v
      {
        Tarjan(v);        //继续往下遍历
        marge(u,v);    //合并v到u上
        标记v被访问过;
        }
        for each(u,e)    //访问所有和u有询问关系的e
       {
          如果e被访问过;
          u,e的最近公共祖先为find(e);
       }
}

2.倍增lca(在线)

#include<bits/stdc++.h>

using namespace std;

const int N=100000;
const int M=1000000;

int dep[N],fa[N][20];

int head[N],tot;
struct node{int v,next;}e[N];
void insert(int u,int v){
    e[++tot]=(node){v,head[u]};head[u]=tot;}

void dfs(int u,int f){
    dep[u]=dep[f]+1;
    fa[u]=f;
    for(int i=head[u];i;i=e[i].next){
        int v=e[i].v;
        dfs(v,u);}
}

int lca(int x,int y){
    int i,j;
    if(dep[x]<dep[y]) swap(x,y);

    for(i=0;(1<<i)<=dep[x];i++);
    --i;

    for(j=i;j>=0;j--)
    if(dep[x]-(1<<j)>=dep[y])
    x=fa[x][j];

    if(x==y) return x;

    for(j=i;j>=0;j--)
    if(fa[x][j]!=fa[y][j])
    x=fa[x][j],y=fa[y][j];

    return fa[x][0];}

int main(){
    int n;cin>>n;
    for(int i=1;i<n;i++){
        int u,v;cin>>u>>v;
        insert(u,v);insert(v,u);}

    dfs(1,0);

    for(int j=1;(1<<j)<=n;j++)
    for(int i=1;i<=n;i++)
    fa[i][j]=fa[fa[i][j-1]][j-1];

    int q;
    cin>>q;
    while(q--){
        int a,b;cin>>a>>b;
        cout<<lca(a,b)<<endl;
    }return 0;
}

3.树剖lca(在线)

void dfs1(int u,int f){
    dep[u]=dep[f]+1;
    siz[u]=1;
    fa[u]=f;
    for(int i=head[u];i;i=e[i].next){
        int v=e[i].v;
        if(v==f) continue;
        dfs1(v,u);
        siz[u]+=siz[v];
        if(siz[son[u]]<siz[v]) son[u]=v;}}

void dfs2(int u,int tp){
    top[u]=tp;   // top就是当前所在链的顶端
    if(!son[u]) return;
    dfs2(son[u],tp);
    for(int i=head[u];i;i=e[i].next){
        int v=e[i].v;
        if(!top[v]) dfs2(v,v);}}

int lca(int x,int y){
    int fx=top[x],fy=top[y];//将x,y放到同一重链上
    while(fx!=fy){
        if(dep[fx]<dep[fy]) swap(x,y),swap(fx,fy);
        x=fa[fx],fx=top[x];}
    return dep[u]<dep[v]?u:v;}//选取深度小的输出

原文地址:https://www.cnblogs.com/asdic/p/9560653.html

时间: 2024-08-24 13:22:25

tarjan,树剖,倍增求lca的相关文章

蓝书4.1-4.4 树状数组、RMQ问题、线段树、倍增求LCA

这章的数据结构题很真实 T1 排队 bzoj 1699 题目大意: 求静态一些区间的最大值-最小值 思路: ST表裸题 1 #include<iostream> 2 #include<cstdio> 3 #include<cstdlib> 4 #include<cstring> 5 #include<cmath> 6 #include<algorithm> 7 #include<queue> 8 #include<v

HDU 4081 Qin Shi Huang&#39;s National Road System 最小生成树+倍增求LCA

原题链接:http://acm.hdu.edu.cn/showproblem.php?pid=4081 Qin Shi Huang's National Road System Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 5428    Accepted Submission(s): 1902 Problem Description

【LCA】倍增求LCA

题目描述 如题,给定一棵有根多叉树,请求出指定两个点直接最近的公共祖先. 输入输出格式 输入格式: 第一行包含三个正整数N.M.S,分别表示树的结点个数.询问的个数和树根结点的序号. 接下来N-1行每行包含两个正整数x.y,表示x结点和y结点之间有一条直接连接的边(数据保证可以构成树). 接下来M行每行包含两个正整数a.b,表示询问a结点和b结点的最近公共祖先. 输出格式: 输出包含M行,每行包含一个正整数,依次为每一个询问的结果. 输入输出样例 输入样例#1: 复制 5 5 4 3 1 2 4

hdu 2586 How far away ? 倍增求LCA

倍增求LCA LCA函数返回(u,v)两点的最近公共祖先 #include <bits/stdc++.h> using namespace std; const int N = 40010*2; struct node { int v,val,next; node(){} node(int vv,int va,int nn):v(vv),val(va),next(nn){} }E[N]; int n,m; int tot,head[N],dis[N],f[N][20],dep[N]; void

P2633|主席树+dfs序+树链剖分求lca+离散化

不知道为什么会RE.. 待补 思路:链上求u和v两点路径第k小利用lca就转变为了 U+V-LCA-FA(LCA) 上的第k小,这因为每个点的主席树的root是从其父转移来的.可以用树链剖分求lca:在dfs序上建立主席树将树上问题转变为区间问题,询问的时候用主席树求区间k小值. 终于能写出这种题了,开心! #include<bits/stdc++.h> using namespace std; const int maxn = 1e5+100; int n,m,e = 1,num,ans=0

51nod2621 树上距离一题四解ST表+倍增+Tarjan+树剖

LCA裸题 只有代码无原理,给自己复习用 1. ST表(这题2^10就够了) 1 #include <bits/stdc++.h> 2 using namespace std; 3 4 const int maxn=2e3+50; 5 6 int cnt,dfn[maxn],dep[maxn],dp[maxn][21],lg2[maxn],dis[maxn],w[maxn][maxn]; 7 std::vector<int> G[maxn]; 8 void dfs(int u,in

【POJ1330】Nearest Common Ancestors(树链剖分求LCA)

Description A rooted tree is a well-known data structure in computer science and engineering. An example is shown below: In the figure, each node is labeled with an integer from {1, 2,...,16}. Node 8 is the root of the tree. Node x is an ancestor of

[luogu3379]最近公共祖先(树上倍增求LCA)

题意:求最近公共祖先. 解题关键:三种方法,1.st表 2.倍增法 3.tarjan 此次使用倍增模板 #include<cstdio> #include<cstring> #include<algorithm> #include<cstdlib> #include<iostream> #include<cmath> using namespace std; typedef long long ll; int n,m,root,cnt

【OI】倍增求LCA

╭(′▽`)╯ 总之,我们都知道lca是啥,不需要任何基础也能想出来怎么用最暴力的方法求LCA,也就是深度深的点先跳到深度浅的点的同一深度,然后一起向上一步步跳.这样显然太慢了! 所以我们要用倍增,倍增比较屌,直接2^k速度往上跳,而且复杂度和树剖lca差不多,那么步骤分为两步 1.让两个点到同一深度 2.到了同一深度同步往上跳 反正我一开始看的时候一直在想,万一跳过了怎么办?哈哈哈,所以说我们有办法嘛: 定义deepv为v点的深度,设两个要求lca的点分别为a,b,且deepa >= deep