zoukankan      html  css  js  c++  java
  • 树上倍增法求LCA

     
    输入
    第一行是单个整数T(T <= 10),表示测试数据的数量。
      对于每个测试数据,在第一行中有两个数字n(2 <= n <= 40000)和m
    (1 <= m <= 200),结点数量和查询数量。下面的n-1行每个包含三个数
    字i,j,k,分隔在一个空格中,这意味着有一条连接结点i和结点j的道路
    长度为k(0 <k <= 40000)。结点是标记为1到n。接下来m行每个都有
    不同的整数i和j,你要回答结点i和结点j之间的距离。
     
    输出
    对于每个测试用例,输出m行。每行代表查询的答案。在每个测试用例后
    输出一条平淡的线。
     
    样例输入

    2
    3 2
    1 2 10
    3 1 15
    1 2
    2 3
    2 2
    1 2 100
    1 2
    2 1

     样例输出

    10

    25

    100

    100

    解析:这是一个LCA模板,求x,y的LCA后计算x,y至LCA(x,y)的距离和,直接写代码(有注释)

    #include<bits/stdc++.h>
    using namespace std;
    struct Edge//结构体求路径 
    {
    	int to,next,val;
    }e[40005];
    int head[40005];
    int tot=1;
    int f[40005][50];
    int g[40005][50];
    int d[40005]; 
    int n,m;
    inline int read()//read快读 
    {
        int x=0,f=1;
        char ch=getchar();
        while(ch<'0'||ch>'9')
    	{
            if(ch=='-')
                f=-1;
            ch=getchar();
        }
        while(ch>='0'&&ch<='9')
    	{
            x=(x<<1)+(x<<3)+(ch^48);
            ch=getchar();
        }
        return x*f;
    }
    inline int Log(int x)//求一个数的log 
    {
    	int i=1;
    	while(1<<i<x)
    	{
    		i++;
    	}
    	return i;
    }
    inline void add(int u,int v,int w)//将一个路径加上 
    {
    	e[tot].to=v;
    	e[tot].val=w;
    	e[tot].next=head[u];
    	head[u]=tot++;
    }
    inline void dfs(int idx,int fa_)//dfs预处理父亲以及到父亲的距离 
    {
    	for(int i=head[idx];i;i=e[i].next)
    	{
    		if(e[i].to!=fa_)
    		{
    			f[e[i].to][0]=idx;
    			g[e[i].to][0]=e[i].val;
    			dfs(e[i].to,idx);
    		}
    	}
    }
    int SS_BZ(int x,int y)//树上倍增函数 
    {
    	int sum=0;
    	if(d[x]<d[y]) //如果x的深度小于y,就先交换x,y,然后将x向上找父亲,直到深度y相同 
    	{
    		swap(x,y);
    		int sum4=0;
    		sum4+=d[x]-d[y];
    		int sum2=sum4;
    		int sum3=0;
    		while(sum2)
    		{
    			if(sum2%2)
    			{
    				sum+=g[x][sum3];
    				x=f[x][sum3];
    			}
    			sum3++;
    			sum2/=2;
    		}
    	}
    	else if(d[x]>d[y]) //如果x的深度大于y,就先直接将x向上找父亲,直到深度y相同 
    	{
    		int sum4=0;
    		sum4+=d[x]-d[y];
    		int sum2=sum4;
    		int sum3=0;
    		while(sum2)
    		{
    			if(sum2%2)
    			{
    				sum+=g[x][sum3];
    				x=f[x][sum3];
    			}
    			sum3++;
    			sum2/=2;
    		}	
    	}
    	while(1)
    	{
    		int i=0;
    		while(f[x][i]!=f[y][i])//如果x的2^i辈祖先= y的2^i辈祖先,则x,y 的LCA的深度>x,y的2^i辈祖先 
    		{
    			i++;
    		}
    		i--;
    		if(i<=0)//如果i的值<=0,则结束 
    		{
    			sum+=(g[x][0]+g[y][0]);
    			break;
    		}
    		sum+=(g[x][i]+g[y][i]);
    		x=f[x][i],y=f[y][i];
    	}
    	return sum;//将x-->LCA(x,y)+LCA(x,y)-->y的值返回 
    }
    int main()
    {
    	int T;
    	scanf("%d",&T);
    	while(T--)//T组数据 
    	{
    		//初始化 
    		tot=1;
    		memset(d,0,sizeof(d));
    		memset(f,0,sizeof(f));
    		memset(e,0,sizeof(e));
    		memset(head,0,sizeof(head));
    		memset(g,0,sizeof(g));
    		n=read(),m=read();
    		int LOG=Log(n);
    		//读入边 
    		for(int i=1;i<=n-1;i++)
    		{
    			int x,y,z;
    			x=read(),y=read(),z=read();
    			add(x,y,z);
    			add(y,x,z);
    		}
    		//预处理 
    		dfs(1,0);
    		for(int i=1;i<=n;i++) f[1][i]=0;
    		for(int i=2;i<=n;i++)
    		{
    			for(int j=1;j<=LOG;j++)
    			{
    				f[i][j]=f[f[i][j-1]][j-1];
    			}
    		}
    		for(int i=1;i<=n;i++) g[1][i]=0;
    		for(int i=2;i<=n;i++)
    		{
    			for(int j=1;j<=LOG;j++)
    			{
    				g[i][j]=g[f[i][j-1]][j-1]+g[i][j-1];
    			}
    		}
    		for(int i=1;i<=n;i++) d[i]=d[f[i][0]]+1;
    		//找x,y的距离并输出 
    		for(int i=1;i<=m;i++)
    		{
    			int x,y;
    			scanf("%d%d",&x,&y);
    			int p=SS_BZ(x,y);
    			printf("%d",p);
    		}
    	}
    	
    	return 0;
    }
    /*
    2
    3 2
    1 2 10
    3 1 15
    1 2
    2 3
    2 2
    1 2 100
    1 2
    2 1
    */
    

      

  • 相关阅读:
    Freezable 对象(WPF)
    排序算法
    属性,构造函数,枚举
    .net 4.0新特性CountDownEvent
    WPF的动画(1)基本动画
    MEF(Managed Extensibility Framework)学习笔记
    WPF依赖属性(续)(4)依赖属性与数据绑定
    [你必须知道的.NET] 第六回:深入浅出关键字base和this
    [你必须知道的.NET] 第三回:历史纠葛:特性和属性
    用命令行部分解决 CNNIC 证书问题
  • 原文地址:https://www.cnblogs.com/chen-1/p/11213076.html
Copyright © 2011-2022 走看看