zoukankan      html  css  js  c++  java
  • HDU 5266 bc# 43 LCA+跳表

    学了一发LCA的倍增算法+跳表维护。

    先说说LCA倍增算法,思路是fa[i][j]求的是i结点的2^j倍的祖先,其中2^0就是父结点了。所以可以递推fa[i][j]=fa[fa[i][j-1]][j-1]。

    当求LCA时,设深度u>v,则先倍增把u提到v的同等深度,若u==v,lca就是u,否则,两点同时倍增,直到最小深度的p[u][j]!=p[v][j],此时他们的父亲p[u][0]即lca。

    可以看大牛http://www.cnblogs.com/OUSUO/p/3805715.html?utm_source=tuicool,先转一发。

    1. DFS预处理出所有节点的深度和父节点
    复制代码
    inline void dfs(int u)
    {
        int i;
        for(i=head[u];i!=-1;i=next[i])  
        {  
            if (!deep[to[i]])
            {            
                deep[to[i]] = deep[u]+1;
                p[to[i]][0] = u; //p[x][0]保存x的父节点为u;
                dfs(to[i]);
            }
        }
    }
    复制代码

    2. 初始各个点的2^j祖先是谁 ,其中2^j(j=0...log(该点深度))倍祖先,1倍祖先就是父亲,2倍祖先是父亲的父亲......。

    复制代码
    void init()
    {
        int i,j;
        //p[i][j]表示i结点的第2^j祖先
        for(j=1;(1<<j)<=n;j++)
            for(i=1;i<=n;i++)
                if(p[i][j-1]!=-1)
                    p[i][j]=p[p[i][j-1]][j-1];//i的第2^j祖先就是i的第2^(j-1)祖先的第2^(j-1)祖先
    }
    复制代码
    3.从深度大的节点上升至深度小的节点同层,如果此时两节点相同直接返回此节点,即lca。
    否则,利用倍增法找到最小深度的p[a][j]!=p[b][j],此时他们的父亲p[a][0]即lca。
    复制代码
    int lca(int a,int b)//最近公共祖先
    {
        int i,j;
        if(deep[a]<deep[b])swap(a,b);
        for(i=0;(1<<i)<=deep[a];i++);
        i--;
        //使a,b两点的深度相同
        for(j=i;j>=0;j--)
            if(deep[a]-(1<<j)>=deep[b])
                a=p[a][j];
        if(a==b)return a;
        //倍增法,每次向上进深度2^j,找到最近公共祖先的子结点
        for(j=i;j>=0;j--)
        {
            if(p[a][j]!=-1&&p[a][j]!=p[b][j])
            {
                a=p[a][j];
                b=p[b][j];
            }
        }
        return p[a][0];
    }
    复制代码
     
     
     
    维护跳表的思想其实和ST算法是一样的,dp[i][j]表示区间i到i+(2^j)-1的LCA,由底往上递推就是dp[i][j]=LCA(dp[i][j-1],dp[i+(1<<j)][j-1])。即可。查询时,也按照跳表查询就可以了。
    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    #include <queue>
    using namespace std;
    
    const int N=300010;
    
    struct Edge{
    	int v,next;
    }edge[N*2];
    int head[N],tot;
    int fa[N][22],dp[N][22];
    int dep[N];
    
    void addedge(int u,int v){
    	edge[tot].v=v;
    	edge[tot].next=head[u];
    	head[u]=tot++;
    }
    
    void BFS(int rt){
    	queue<int>que;
    	que.push(rt);
    	fa[rt][0]=-1; dep[rt]=1;
    	while(!que.empty()){
    		int u=que.front();
    		que.pop();
    		for(int i=1;i<=20;i++){
    			if(fa[u][i-1]!=-1){
    				fa[u][i]=fa[fa[u][i-1]][i-1];
    			}
    		}
    		for(int e=head[u];e!=-1;e=edge[e].next){
    			int v=edge[e].v;
    			if(dep[v]==0){
    				dep[v]=dep[u]+1;
    				fa[v][0]=u;
    				que.push(v);
    			}
    		}
    	}
    }
    
    int LCA(int u,int v){
    	int i,j;
    	if(dep[u]<dep[v])swap(u,v);
    	for(i=0;(1<<i)<=dep[u];i++);
    	i--;
    	for(j=i;j>=0;j--){
    		if(dep[u]-(1<<j)>=dep[v])
    		u=fa[u][j];
    	}
    	if(u==v) return u;
    	for(j=i;j>=0;j--){
    		if(fa[u][j]!=-1&&fa[u][j]!=fa[v][j]){
    			u=fa[u][j];
    			v=fa[v][j];
    		}
    	}
    	return fa[u][0];
    }
    
    int main(){
    	int n,q,u,v;
    	while(scanf("%d",&n)!=EOF){
    		memset(head,-1,sizeof(head));
    		tot=0;
    		memset(fa,-1,sizeof(fa));
    		for(int i=1;i<n;i++){
    			scanf("%d%d",&u,&v);
    			addedge(u,v);
    			addedge(v,u);
    		}
    		memset(dep,0,sizeof(dep));
    		BFS(1);
    	//	cout<<LCA(1,5)<<endl;
    	//	cout<<LCA(2,3)<<endl;
    		for(int i=1;i<=n;i++)
    		dp[i][0]=i;
    		for(int j=1;j<=20;j++){
    			for(int i=1;i+(1<<j)-1<=n;i++)
    			dp[i][j]=LCA(dp[i][j-1],dp[i+(1<<(j-1))][j-1]);
    		}
    /*		for(int i=1;i<=n;i++){
    			for(int j=0;j<=6;j++)
    			cout<<dp[i][j]<<" ";
    			cout<<endl;
    		}*/
    		scanf("%d",&q);
    		while(q--){
    			scanf("%d%d",&u,&v);
    	//		if(u>v) swap(u,v);
    			if(u==v)
    			printf("%d
    ",u);
    			else{
    				int ans=u;
    				for(int i=20;i>=0;i--){
    					if(u+(1<<i)-1<=v){
    						ans=LCA(ans,dp[u][i]);
    						u=u+(1<<i);
    					}
    				}
    				printf("%d
    ",ans);
    			}
    		}
    	}
    	return 0;
    }
    

      

  • 相关阅读:
    POJ 1703 Find them, Catch them
    POJ 2236 Wireless Network
    POJ 2010 Moo University
    POJ 2184 Cow Exhibition
    POJ 3280 Cheapest Palindrome
    POJ 3009 Curling 2.0
    POJ 3669 Meteor Shower
    POJ 2718 Smallest Difference
    POJ 3187 Backward Digit Sums
    POJ 3050 Hopscotch
  • 原文地址:https://www.cnblogs.com/jie-dcai/p/4560174.html
Copyright © 2011-2022 走看看