LCA模板(tarjan离线算法,倍增在线算法)

tarjan:

利用用并查集的高效,与父节点合并
一次性查询O(n+q).
对应模板题hdu2856

#include<map>
#include<set>
#include<cmath>
#include<stack>
#include<queue>
#include<cstdio>
#include<string>
#include<vector>
#include<cstring>
#include<iomanip>
#include<sstream>
#include<iostream>
#include<algorithm>
#define INF 0x3f3f3f3f
#define ls l,m,rt<<1
#define rs m+1,r,rt<<1|1
//#define ll __int64
//#define int ll
typedef  long long ll;
typedef unsigned long long ull;
const int MAXN=4e4+10;
const int MOD=1e9+7;
const double eps=1e-6;
const double finf=1e10;
using namespace std;
template<class T>inline void read(T &res)
{
    
    
    char c;T flag=1;
    while((c=getchar())<'0'||c>'9')if(c=='-')flag=-1;res=c-'0';
    while((c=getchar())>='0'&&c<='9')res=res*10+c-'0';res*=flag;
}
//-------------------------------------------//
struct node
{
    
    
    int to,no;
    node(int a=0,int b=0):to(a),no(b){
    
    }
};
vector<node> qu[MAXN],g[MAXN];
int vis[MAXN],pre[MAXN],ans[MAXN],dis[MAXN];
int unfind(int x)
{
    
    
    return x==pre[x]?x:pre[x]=unfind(pre[x]);
}
void _merge(int a,int b)
{
    
    
    int x=unfind(a);
    int y=unfind(b);
    if(a!=b)pre[a]=b;
}
void tarjan(int u)
{
    
    
    vis[u]=1;
    for(int i=0;i<g[u].size();++i)
    {
    
    
        int v=g[u][i].to,w=g[u][i].no;
        if(vis[v])continue;
        dis[v]=dis[u]+w;
        tarjan(v);
        _merge(v,u);
    }
    for(int i=0;i<qu[u].size();++i)
    {
    
    
        node x=qu[u][i];//cout<<u<<endl;
        if(!vis[x.to])continue;
        ans[x.no]=dis[u]+dis[x.to]-2*dis[unfind(x.to)];
    }
}
void init()
{
    
    
    memset(vis,0,sizeof vis);
    for(int i=0;i<MAXN;++i)
    {
    
    
        pre[i]=i;
        g[i].clear();
        qu[i].clear();
    }
}
int main()
{
    
    
    int t;
    read(t);
    while(t--)
    {
    
    
        int n,m;
        read(n);read(m);
        init();
        for(int i=0;i<n-1;++i)
        {
    
    
            int u,v,w;
            read(u);read(v);read(w);
            g[u].push_back(node(v,w));
            g[v].push_back(node(u,w));
        }
        for(int i=0;i<m;++i)
        {
    
    
            int u,v;
            read(u);read(v);
            qu[u].push_back(node(v,i));
            qu[v].push_back(node(u,i));
        }
        tarjan(1);
        for(int i=0;i<m;++i)printf("%d\n",ans[i]);
    }
    return 0;
}

倍增

用二进制的思想跳跃式查找
预处理复杂度O(nlogn),单次查询复杂度O(logn).
对应模板题 洛谷P3379

#include<map>
#include<set>
#include<cmath>
#include<stack>
#include<queue>
#include<cstdio>
#include<string>
#include<vector>
#include<cstring>
#include<iomanip>
#include<sstream>
#include<iostream>
#include<algorithm>
#define INF 0x3f3f3f3f
#define ls l,m,rt<<1
#define rs m+1,r,rt<<1|1
//#define ll __int64
//#define int ll
typedef  long long ll;
typedef unsigned long long ull;
const int MAXN=5e5+10;
const int MOD=1e9+7;
const double eps=1e-6;
const double finf=1e10;
using namespace std;
template<class T>inline void read(T &res)
{
    
    
    char c;T flag=1;
    while((c=getchar())<'0'||c>'9')if(c=='-')flag=-1;res=c-'0';
    while((c=getchar())>='0'&&c<='9')res=res*10+c-'0';res*=flag;
}
//-------------------------------------------//
int depth[MAXN],fa[MAXN][20],n,m,s;
vector<int> g[MAXN];
void dfs(int u,int pre,int d)
{
    
    
    depth[u]=d;
    fa[u][0]=pre;
    for(int i=0;i<g[u].size();++i)
    {
    
    
        int v=g[u][i];
        if(v!=pre)dfs(v,u,d+1);
    }
}
void init()
{
    
    
    dfs(s,-1,0);
    for(int i=0;(1<<(i+1))<n;++i)
        for(int j=1;j<=n;++j)
        {
    
    
            if(fa[j][i]<0)fa[j][i+1]=-1;
            else fa[j][i+1]=fa[fa[j][i]][i];
        }
}
int LCA(int u,int v)
{
    
    
    if(depth[u]>depth[v])swap(u,v);
    int temp=depth[v]-depth[u];
    for(int i=0;(1<<i)<=temp;++i)
        if((1<<i)&temp)v=fa[v][i];
    if(u==v)return u;
    for(int i=(int)log2(n*1.0);i>=0;--i)
    {
    
    
        if(fa[u][i]!=fa[v][i])
        {
    
    
            u=fa[u][i];
            v=fa[v][i];
        }
    }
    return fa[u][0];
}
int main()
{
    
    
    //freopen("input.txt","r",stdin);
    while(~scanf("%d%d%d",&n,&m,&s))
    {
    
    
        for(int i=0;i<=n;++i)g[i].clear();
        for(int i=0;i<n-1;++i)
        {
    
    
            int u,v;
            read(u);read(v);
            g[u].push_back(v);
            g[v].push_back(u);
        }
        init();
        while(m--)
        {
    
    
            int u,v;
            read(u);read(v);
            printf("%d\n",LCA(u,v));
        }
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_43638337/article/details/103540448