LCA算法 在线树上倍增模板

测试数据

1 10 1
1 2 2
1 4 4
2 3 3
2 5 6
3 7 1
3 8 2
5 6 3
6 9 2 
4 10 4
9 10

终于造了什么事树上倍增了下午考pat。。。哭卿卿

代码理解来自 自己又加了备注。。。。 建议模拟一下

https://blog.csdn.net/a601025382s/article/details/10615039 

#pragma comment(linker, "/STACK:1024000000,1024000000")  
#include<bits/stdc++.h> 
using namespace std;
const int maxn=40004;
struct node{
    int to,w;
    node(int a=0,int b = 0){to=a;w=b;}
};
vector<node>e[maxn];
int f[maxn],dis[maxn],deep[maxn],p[maxn][20],n;
void dfs(int u,int pre,int t)
{
    int i,num;
    deep[u]=t;//深度
    f[u]=pre;//父节点
    num=e[u].size();
    for(i=0;i<num;i++)
    {
        int v=e[u][i].to;
        if(v!=pre)
        {
            dis[v]=dis[u]+e[u][i].w;//距离跟的距离
            dfs(v,u,t+1);
        }
    }
}
void init()
{
    //p[i][j]表示i结点的第2^j祖先
    int i, j;
    for(j = 1;(1 << j) <= n; j++)
        for(i = 1;i <= n; i++)
        p[i][j] = -1; //都初始化为-1
    for(i = 1;i <= n; i++)
		p[i][0] = f[i];
    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)祖先
		}
	}
}
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];
		}
    } //找到与b同层的或者说 b没有同层的 那么就找他的上一层 不用担心p[a][j]是否等于-1 肯定有 
    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];
        }
    }
    /*如果说都是相等的话 那么说明a b在两个子树的左右子树下面 所以直接返回一个子树的根节点就行  
      如果说是有不相等的话 那么就两个节点各自更新成他们的p[a][j] 和 p[b][j] 
    */ 
    return f[a]; 
 
}
int main()
{
    int m,i,a,b,c,ans;
    scanf("%d%d",&n,&m);
    for(i=1;i<=n;i++)e[i].clear();
    for(i=1;i<n;i++)
    {
        scanf("%d%d%d",&a,&b,&c);
        e[a].push_back(node(b,c));
        e[b].push_back(node(a,c));
    }
    dis[1]=0;
    dfs(1,-1,0);//找到各点的深度和各点的父节点以及距离根的距离
//	cout<<"dis"<<endl;
//	for(int i = 0 ; i <= n ; i ++)
//		printf("%d%c",dis[i]," \n"[i==n]);
//	cout<<"deep"<<endl;
//	for(int i = 0 ; i <= n ; i ++)
//		printf("%d%c",deep[i]," \n"[i==n]);
//	cout<<"f"<<endl;
//	for(int i = 0 ; i <= n ; i ++)
//		printf("%d%c",f[i]," \n"[i==n]);
    init();     //初始各个点的2^j祖先是谁    
    for(i=0;i<m;i++)
    {
        scanf("%d%d",&a,&b);
        cout<<lca(a,b)<<endl;
    }
    return 0;
}
/*
    最近公共祖先lca,在线算法/倍增法,模板题。套别人模板自己敲了遍,现在还要回顾下邻接表,哎。。
    用vector,发现爆栈了,汗一个。。
    用#pragma comment(linker, "/STACK:1024000000,1024000000") 开个把栈开大点吧。。hdu可以,别的地方就不清楚了
*/
/*
1 10 7
1 2 2
1 4 4
2 3 3
2 5 6
3 7 1
3 8 2
5 6 3
6 9 2 
4 10 4
*/

猜你喜欢

转载自blog.csdn.net/galesaur_wcy/article/details/84920880