zoukankan      html  css  js  c++  java
  • [洛谷P3379]【模板】最近公共祖先(LCA)

    题目大意:就是叫你求最近公共祖先。

    最近刚学了倍增,于是用这道模板题来练练。

    有人说倍增写法要读入优化,要卡常,然而经过我的测试,发现并不需要(尽管我加了读优,比原来的要快400+ms)。

    C++ Code:

    #include<cstdio>
    #include<cstring>
    #include<cctype>
    using namespace std;
    int n,m,s;
    int head[1000005],next[1000005],to[1000005],cnt=0,deep[500005],p[500005][20];
    void addedge(int x,int y){
    	cnt++;
    	to[cnt]=y;
    	next[cnt]=head[x];
    	head[x]=cnt;
    	cnt++;
    	to[cnt]=x;
    	next[cnt]=head[y];
    	head[y]=cnt;
    }
    void dfs(int u){
    	for(int i=head[u];i;i=next[i])
    	if(!deep[to[i]]){
    		deep[to[i]]=deep[u]+1;
    		p[to[i]][0]=u;
    		dfs(to[i]);
    	}
    }
    void init(){
    	for(int j=1;(1<<j)<=n;j++)
    	for(int i=1;i<=n;i++)
    	if(p[i][j-1]!=-1)p[i][j]=p[p[i][j-1]][j-1];
    }
    int lca(int x,int y){
    	int i;
    	if(deep[x]<deep[y])x^=y,y^=x,x^=y;
    	for(i=0;(1<<i)<=deep[x];i++);i--;
    	for(int j=i;j>=0;j--)
    	if(deep[p[x][j]]>=deep[y])x=p[x][j];
    	if(x==y)return x;
    	for(int j=i;j>=0;j--)
    	if(p[x][j]!=-1&&p[x][j]!=p[y][j])x=p[x][j],y=p[y][j];
    	return p[x][0];
    }
    #define C c=getchar()
    int readint(){
    	int C;
    	while(!isdigit(c))C;
    	int p=0;
    	while(isdigit(c)){
    		p=p*10+c-'0';
    		C;
    	}
    	return p;
    }
    int main(){
    	n=readint(),m=readint(),s=readint();
    	memset(p,-1,sizeof(p));
    	for(int i=1;i<n;i++)addedge(readint(),readint());
    	deep[s]=1;
    	dfs(s);
    	init();
    	while(m--)printf("%d
    ",lca(readint(),readint()));
    	return 0;
    }
    

    另外附上以前写的Tarjan,比倍增快了1000+ms(尽管我也不相信倍增比Tarjan慢,然而事实就是这样)。

    C++ Code:

     

    #include<cstdio>
    #include<cstring>
    #include<vector>
    #include<cctype>
    using namespace std;
    int n,m,ne=0,nq=0;
    bool vis[500001],instack[500001];
    int f[500001],head[500001],que[500001],ans[500001];
    struct query{
        int same,next,to,num;
        bool flag;
    }q[1000001];
    struct edge{
        int to,next;
    }e[1000001];
    void add_edge(int x,int y){
        e[++ne].to=y;
        e[ne].next=head[x];
        head[x]=ne;
        e[++ne].to=x;
        e[ne].next=head[y];
        head[y]=ne;
    }
    void add_que(int x,int y,int z){
        q[++nq].to=y;
        q[nq].same=nq+1;
        q[nq].num=z;
        q[nq].next=que[x];
        que[x]=nq;
        q[++nq].to=x;
        q[nq].same=nq-1;
        q[nq].num=z;
        q[nq].next=que[y];
        que[y]=nq;
    }
    int find(int x){
        if(f[x]==x)return x;
        return f[x]=find(f[x]);
    }
    void tarjan(int root){
        instack[root]=true;
        for(int i=head[root];i;i=e[i].next){
            int v=e[i].to;
            if(instack[v])continue;
            tarjan(v);
            f[v]=root;
            vis[v]=true;
        }
        for(int i=que[root];i;i=q[i].next)
        if(vis[q[i].to]&&!q[i].flag){
            ans[q[i].num]=find(q[i].to);
            q[i].flag=q[q[i].same].flag=true;
            
        }
        instack[root]=false;
    }
    #define C c=getchar()
    int readint(){
        char C;
        while(!isdigit(c))C;
        int d=0;
        while(isdigit(c)){
            d=d*10+c-'0';
            C;
        }
        return d;
    }
    int main(){
        int t;
        n=readint(),m=readint(),t=readint();
        memset(vis,0,sizeof(vis));
        memset(instack,0,sizeof instack);
        for(int i=1;i<=n;i++)f[i]=i;
        for(int i=1;i<n;i++){
            int u=readint(),v=readint();
            add_edge(u,v);
        }
        for(int i=1;i<=m;i++){
            int x=readint(),y=readint();
            add_que(x,y,i);
        }
        tarjan(t);
        for(int i=1;i<=m;i++)
        printf("%d
    ",ans[i]);
        return 0;
    }
    

      ----------------------------------------------------------2017.7.13----------------------------------------------------------

    最近学了树链剖分,于是用树剖写了个LCA,不过速度居然没有Tarjan快。

    C++ Code:

     

    #include<cstdio>
    #include<cctype>
    #include<algorithm>
    using std::swap;
    #define C c=getchar()
    int n,m,s;
    int head[500005],next[1000005],cnt=0,to[1000005],deep[500005],fa[500005],sz[500005],top[500005];
    inline int readint(){
    	char C;
    	while(!isdigit(c))C;
    	int p=0;
    	while(isdigit(c))p=p*10+c-'0',C;
    	return p;
    }
    inline void addedge(int u,int v){
    	to[++cnt]=v;
    	next[cnt]=head[u];
    	head[u]=cnt;
    	to[++cnt]=u;
    	next[cnt]=head[v];
    	head[v]=cnt;
    }
    void dfs(int x){
    	deep[x]=deep[fa[x]]+1;
    	sz[x]=1;
    	for(int i=head[x];i;i=next[i])
    	if(fa[x]!=to[i]){
    		fa[to[i]]=x;
    		dfs(to[i]);
    		sz[x]+=sz[to[i]];
    	}
    }
    void dfs2(int x){
    	if(!top[x])top[x]=x;
    	int t=0;
    	for(int i=head[x];i;i=next[i])
    	if(fa[x]!=to[i]&&sz[to[i]]>sz[t])t=to[i];
    	if(t)top[t]=top[x],dfs2(t);
    	for(int i=head[x];i;i=next[i])
    	if(fa[x]!=to[i]&&to[i]!=t)dfs2(to[i]);
    }
    int query(int x,int y){
    	for(;top[x]!=top[y];x=fa[top[x]])
    	if(deep[top[x]]<deep[top[y]])swap(x,y);
    	return deep[x]<deep[y]?x:y;
    }
    int main(){
    	n=readint(),m=readint(),s=readint();
    	for(int i=1;i<n;++i)addedge(readint(),readint());
    	dfs(s);dfs2(s);
    	while(m--)printf("%d
    ",query(readint(),readint()));
    	return 0;
    }
    
  • 相关阅读:
    ArrayList用法
    MessageBox
    将文本文件导入Sql数据库
    在桌面和菜单中添加快捷方式
    泡沫排序
    Making use of localized variables in javascript.
    Remove double empty lines in Visual Studio 2012
    Using Operations Manager Connectors
    Clear SharePoint Designer cache
    Programmatically set navigation settings in SharePoint 2013
  • 原文地址:https://www.cnblogs.com/Mrsrz/p/7153725.html
Copyright © 2011-2022 走看看