关于在搜索中进行倍增数组初始化的疑问
查看原帖
关于在搜索中进行倍增数组初始化的疑问
231543
bloodstalk楼主2022/7/2 16:08

下面的是一个AC代码

#include<bits/stdc++.h>
#define ll long long 
#define il inline
#define re register
const int N=500005;
using namespace std;

int depth[N],parents[N][23];
int n,m,s,u,v,root;

struct node
{
	int fa;
	int number;
}now,endd;

queue <node> q;
vector <int> g[N];

il int read()
{
	int f=0,s=0;
	char ch=getchar();
	for(;!isdigit(ch);ch=getchar()) f |= (ch=='-');
	for(;isdigit(ch);ch=getchar()) s = (s<<1) + (s<<3) + (ch^48);
	return f ? -s : s;
}

il void bfs(int x)
{
	now.fa=0;now.number=x;
	q.push(now);
	int num;
	while(!q.empty())
	{
		now=q.front();
		q.pop();
		num=now.number;
		for(int j=1;j<=22;j++)
			parents[num][j]=parents[parents[num][j-1]][j-1];
		for(int j=0;j<g[num].size();j++)
		{
			int e=g[num][j];
			if(e==now.fa) continue;
			depth[e]=depth[num]+1;
			endd.number=e;
			endd.fa=num;
			parents[e][0]=num;
			q.push(endd);
		}
	}
}

/*il void Multiply()
{
	for(re int u=1;u<=n;u++)
		for(re int up=1;up<=22;up++)
			parents[u][up]=parents[parents[u][up-1]][up-1];
}*/

int LCA(int x,int y)
{
	if(depth[x] < depth[y]) swap(x,y);
	for(re int i=22;i>=0;i--)
		if(depth[parents[x][i]] >= depth[y]) x=parents[x][i];
	if(x == y) return x;
	for(re int i=22;i>=0;i--)
	{
		if(parents[x][i] != parents[y][i])
		{
			x=parents[x][i];
			y=parents[y][i];	
		}	
	}
	return parents[x][0];
}

int main()
{
	n=read(),m=read(),s=read();
//	memset(parents,-1,sizeof parents);
//	memset(depth,-1,sizeof depth);
	for(re int i=1;i<=n-1;i++)
	{
		u=read(),v=read();
		g[u].push_back(v);
		g[v].push_back(u);
	}
	depth[s]=1;
	parents[s][0]=0;
	bfs(s);
	//Multiply();
	for(re int i=1;i<=m;i++)
	{
		u=read(),v=read();
		printf("%d\n",LCA(u,v));
	}
	return 0;
}

我选择在bfs中进行初始化,下面是一个WA代码的部分片段


il void Multiply()
{
	for(re int up=1;up<=22;up++)
		for(re int u=1;u<=n;u++)
			parents[u][up]=parents[parents[u][up-1]][up-1];
}

int LCA(int x,int y)
{
	if(depth[x] < depth[y]) swap(u,v);
	for(re int i=22;i>=0;i--)
		if(depth[parents[x][i]] >= depth[y]) u=parents[x][i];
	if(x == y) return x;
	for(re int i=22;i>=0;i--)
	{
		if(parents[x][i] != parents[y][i])
		{
			x=parents[x][i];
			y=parents[y][i];	
		}	
	}
	return parents[x][0];
}

下面是另一个AC片段

void increase()
{
	for(int up=1;(1<<up)<=n;up++)
		for(int u=1;u<=n;u++)
			parents[u][up]=parents[parents[u][up-1]][up-1];
}

int lca(int u,int v)
{
	if(depth[u]<depth[v]) swap(u,v);
	int maxjump=-1,j;
	while((1<<(maxjump+1)) <= depth[u]) ++maxjump;
	for(int i=maxjump;i>=0;i--)
		if(depth[u]- (1<<i) >= depth[v]) u=parents[u][i];
	if(u==v) return u;
	for(int i=maxjump;i>=0;i--)
	{
		if(parents[u][i] != parents[v][i])
		{
			u=parents[u][i];
			v=parents[v][i];	
		}	
	}
	return parents[u][0];
}

int main()
{
	...
	depth[s]=1;
	parents[s][0]=s;
	search(s);
	increase();
	... 
}

代码可能有点长。通过我的研究第二个代码的问题是在multiply函数中有可能我先遍历到的是儿子节点再是父亲节点,导致错误。于是我就选择了第一个代码的方式,在bfs中进行初始化 parents 数组,使其有序,然后就AC了。于是我翻出了我之前写的AC过的LCA模板,我依旧是用的Multiply函数,并且这个代码是AC的,我想请问是因为我在第三个代码中用了maxjump的原因使其不出错吗,如果不是,请问是什么原因导致的第二份代码和第三份代码的差异?

2022/7/2 16:08
加载中...