Luogu-P3379 [Template] Nearest Common Ancestor (LCA) (RMQ for LCA/Tarjan for LCA)

Topic link: click to view

The main idea of ​​the topic: give a rooted tree composed of n points, and then give m queries, each query needs to answer the lca of point x and point y

Problem analysis: Today I learned two very interesting methods for LCA. Summarize the pros and cons of the four methods. Refer to my own for the complexity of the implementation. If there is a code boss who can close his eyes and write casually, just ignore it. Orz

Multiplying the tree for LCA:

  1. time complexity:
    1. Preprocessing: O( nlogn)
    2. Query: O( logn)
  2. Space complexity: O( nlogn)
  3. Implementation complexity: the simplest

Find LCA for tree chain division:

  1. time complexity:
    1. Preprocessing: O( n)
    2. Query: O( logn)
  2. Space complexity: O(logn)
  3. Implementation complexity: the most difficult to write

RMQ asks for LCA:

  1. time complexity:
    1. Preprocessing: O( nlogn)
    2. Query: O( 1)
  2. Space complexity: O( nlogn)
  3. Implementation complexity: relatively simple

Tarjan asks for LCA (offline):

  1. Time complexity: O( n)
  2. Space complexity: O( n)
  3. Implementation complexity: relatively simple

In general, the current mainstream of LCA is tree multiplication and tree chain division. The tree multiplication is the simplest to achieve, the tree chain division constant is the smallest, and some problems will get stuck in the log, so sometimes Tarjan is also used offline. Please, as for RMQ, I don’t know when to use it. .

Code:

Tarjan:

//#pragma GCC optimize(2)
//#pragma GCC optimize("Ofast","inline","-ffast-math")
//#pragma GCC target("avx,sse2,sse3,sse4,mmx")
#include<iostream>
#include<cstdio>
#include<string>
#include<ctime>
#include<cmath>
#include<cstring>
#include<algorithm>
#include<stack>
#include<climits>
#include<queue>
#include<map>
#include<set>
#include<sstream>
#include<cassert>
#include<bitset>
using namespace std;
     
typedef long long LL;
     
typedef unsigned long long ull;
     
const int inf=0x3f3f3f3f;

const int N=1e6+100;

vector<pair<int,int>>qu[N];

vector<int>node[N];

int fa[N],ans[N];

bool vis[N];

int find(int x)
{
	return fa[x]==x?x:fa[x]=find(fa[x]);
}

void tarjan(int u,int f)
{
	fa[u]=u;
	for(auto v:node[u])
	{
		if(v==f)
			continue;
		tarjan(v,u);
		fa[v]=u;
	}
	vis[u]=true;
	for(auto it:qu[u])
	{
		int v=it.first,id=it.second;
		if(vis[v])
			ans[id]=find(v);
	}
}

int main()
{
#ifndef ONLINE_JUDGE
//  freopen("data.in.txt","r",stdin);
//  freopen("data.out.txt","w",stdout);
#endif
//  ios::sync_with_stdio(false);
	int n,m,root;
	scanf("%d%d%d",&n,&m,&root);
	for(int i=1;i<n;i++)
	{
		int u,v;
		scanf("%d%d",&u,&v);
		node[u].push_back(v);
		node[v].push_back(u);
	}
	for(int i=1;i<=m;i++)
	{
		int u,v;
		scanf("%d%d",&u,&v);
		qu[u].emplace_back(v,i);
		qu[v].emplace_back(u,i);
	}
	tarjan(root,-1);
	for(int i=1;i<=m;i++)
		printf("%d\n",ans[i]);








    return 0;
}

RMQ:

//#pragma GCC optimize(2)
//#pragma GCC optimize("Ofast","inline","-ffast-math")
//#pragma GCC target("avx,sse2,sse3,sse4,mmx")
#include<iostream>
#include<cstdio>
#include<string>
#include<ctime>
#include<cmath>
#include<cstring>
#include<algorithm>
#include<stack>
#include<climits>
#include<queue>
#include<map>
#include<set>
#include<sstream>
#include<cassert>
#include<bitset>
using namespace std;
     
typedef long long LL;
     
typedef unsigned long long ull;
     
const int inf=0x3f3f3f3f;

const int N=1e6+100;

vector<int>node[N];

int dfn[N],id[N][25],deep[N],cnt,lg2[N];

void dfs(int u,int fa,int dep)
{
	deep[u]=dep;
	dfn[u]=++cnt;
	id[cnt][0]=u;
	for(auto v:node[u])
	{
		if(v==fa)
			continue;
		dfs(v,u,dep+1);
		id[++cnt][0]=u;
	}
}

void RMQ()
{
	for(int i=2;i<=cnt;i++)
		lg2[i]=lg2[i>>1]+1;
	for(int j=1;j<=20;j++)
		for(int i=1;(i+(1<<j)-1)<=cnt;i++)
		{
			int l=i,r=i+(1<<(j-1));
			id[i][j]=deep[id[l][j-1]]<deep[id[r][j-1]]?id[l][j-1]:id[r][j-1];
		}
}

int query(int x,int y)
{
	int l=dfn[x],r=dfn[y];
	if(l>r)
		swap(l,r);
	int k=lg2[r-l+1];
	return deep[id[l][k]]<deep[id[r-(1<<k)+1][k]]?id[l][k]:id[r-(1<<k)+1][k];
}

int main()
{
#ifndef ONLINE_JUDGE
//  freopen("data.in.txt","r",stdin);
//  freopen("data.out.txt","w",stdout);
#endif
//  ios::sync_with_stdio(false);
	int n,m,root;
	scanf("%d%d%d",&n,&m,&root);
	for(int i=1;i<n;i++)
	{
		int u,v;
		scanf("%d%d",&u,&v);
		node[u].push_back(v);
		node[v].push_back(u);
	}
	dfs(root,0,0);
	RMQ();
	while(m--)
	{
		int x,y;
		scanf("%d%d",&x,&y);
		printf("%d\n",query(x,y));
	}











    return 0;
}

 

Guess you like

Origin blog.csdn.net/qq_45458915/article/details/109317063
lca