zoukankan      html  css  js  c++  java
  • 人工栈——解决爆栈难题

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

    node (dfs)(dfs)

    #include<cstdio>
    #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
    ",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<cstdio>
    #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
    ",lca[i]);
    	return 0;
    }
    
    转载需注明出处。
  • 相关阅读:
    闭包 与 装饰器
    Linux常用命令 (二)
    day1 linux常用命令(一)
    📎 .xib
    📎 Emoji 前端转换
    📎 钉钉微应用( 新启项目Weex H5 )
    📎 ROR:常用GEM
    📎 AndroidNative【ING...】
    🆕 ror方法
    安装centos7
  • 原文地址:https://www.cnblogs.com/jz929/p/11817609.html
Copyright © 2011-2022 走看看