人工栈——解决爆栈难题

我们便以tarjan_LCA为模板,顺便复习复习tarjan_LCA。

node ( d f s ) (dfs) (dfs)

#include
#define N 500010 
using namespace std;
struct node{int v,fr;}e[N<<1];
struct edge{int v,fr,num;}g[N<<1];
int tail[N],head[N],lca[N],fa[N];
int n,m,s,cnt=0,cnt1=0;
bool bz[N];

inline int read()
{
	int x=0; char c=getchar();
	while (c<'0' || c>'9') c=getchar();
	while (c>='0' && c<='9') x=(x<<1)+(x<<3)+(c^48),c=getchar();
	return x;
}

inline void add(int u,int v) {e[++cnt]=(node){v,tail[u]}; tail[u]=cnt;}

inline void add1(int u,int v,int num) {g[++cnt1]=(edge){v,head[u],num},head[u]=cnt1;}

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

void dfs(int x)
{
	for (int p=head[x],v;p;p=g[p].fr)
	{
		v=g[p].v;
		if (!bz[v]) continue;
		lca[g[p].num]=find(v);
	}
	for (int p=tail[x],v;p;p=e[p].fr)
	{
		v=e[p].v;
		if (bz[v]) continue;
		bz[v]=1,dfs(v),fa[v]=x;
	}
}

int main()
{
	freopen("tarjan.in","r",stdin);
	freopen("tarjan.out","w",stdout);
	n=read(),m=read(),s=read();
	for (int i=1,u,v;i<n;i++)
		u=read(),v=read(),add(u,v),add(v,u);
	for (int i=1,u,v;i<=m;i++)
		u=read(),v=read(),add1(u,v,i),add1(v,u,i);
	bz[s]=1,dfs(s);
	for (int i=1;i<=m;i++) printf("%d\n",lca[i]);
	return 0;
}

这便是模板了(来源于jz_junior_oj_2263. 最近公共祖先(LCA))
然后我们来看一看如何打人工栈。
人工栈,顾名思义,就是人为的去模拟栈这个东东。
我们要如何来模拟dfs呢?我们就按照dfs的性质来想想。
它是不停地往下递归,所以我们也要如此
我们用前向星来存储询问和边。
每次走完一条边,我们就将tail数组更新一番。
下面大概模拟一下这个过程:

//dfs版
void dfs(int x)
{
	'A';
	for (int p=tail[x];p;p=e[p].fr)
		if ('B')
		{
//			此处相当于'A'
			dfs(e[p].v);
			'C';
		}
//	此处相当于'C'
}
//人工栈版
while (top)
{
	x=z[top];to=e[tail[x]].v;
	while (!'B')
		tail[x]=e[tail[x]].fr,to=e[tail[x]].v;
	if (!tail[x])
	{
		'C';
		top--;
		continue;
	}
	'A';
	z[++top]=to;
}

大概就是这样子的了,下面来看一看模板(开始的LCA)改成人工栈后的样子吧!

node ( 人 工 栈 ) (人工栈) ()

#include
#define N 500010 
using namespace std;
struct node{int v,fr;}e[N<<1];
struct edge{int v,fr,num;}g[N<<1];
int tail[N],head[N],lca[N],fa[N],fat[N],z[N];
int n,m,s,cnt=0,cnt1=0,top,x,to;
bool bz[N];

inline int read()
{
	int x=0; char c=getchar();
	while (c<'0' || c>'9') c=getchar();
	while (c>='0' && c<='9') x=(x<<1)+(x<<3)+(c^48),c=getchar();
	return x;
}

inline void add(int u,int v) {e[++cnt]=(node){v,tail[u]}; tail[u]=cnt;}

inline void add1(int u,int v,int num) {g[++cnt1]=(edge){v,head[u],num},head[u]=cnt1;}

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

int main()
{
	freopen("tarjan.in","r",stdin);
	freopen("tarjan.out","w",stdout);
	n=read(),m=read(),s=read();
	for (int i=1,u,v;i<n;i++)
		u=read(),v=read(),add(u,v),add(v,u);
	for (int i=1,u,v;i<=m;i++)
	{
		u=read(),v=read();
		if (u==v) {lca[i]=u; continue;}
		add1(u,v,i),add1(v,u,i);
	}
	bz[s]=1;z[1]=s,top=1;
	while (top)
	{
		x=z[top];
		to=e[tail[x]].v;
		while (tail[x] && bz[to])
			tail[x]=e[tail[x]].fr,to=e[tail[x]].v;
		if (!tail[x]) {fa[x]=fat[x],top--; continue;}
		bz[to]=1,z[++top]=to,fat[to]=x;
		for (int p=head[to],v;p;p=g[p].fr)
		{
			v=g[p].v;
			if (!bz[v]) continue;
			lca[g[p].num]=gf(v);
		}
	}
	for (int i=1;i<=m;i++) printf("%d\n",lca[i]);
	return 0;
}

你可能感兴趣的:(总结,人工栈)