LCA

总结lca

Lca的主要功能是找最近公共祖先。提到祖先,最容易想起的是x叉树。

首先,要给每一个结点都编号,按照先序遍历。

 

因此,可以开一个数组,记录发现时间found,time++但是要注意,在编程时不能用time这个变量,与某个函数冲突。

 

    当我们找3和4的公共祖先时,我们会发现,当找到1那里时,会发现,found[1]一定小于found[3],那么说明找过头了。那如果找到4那里的话,又会发现found[4]大于found[3]。

    这么一来,和我们以前学过的二分挺像的,先跳上去step=(lo+hi)/2 ; mid=up(b,step),由b结点跳这么多步。如果跳过头了,那么hi=mid,反之lo=mid。

    但是,真的是这样吗?当我们要跳step步时,并不一定是我们已经算出来的1、2、4,所以,要执行up(b,step)是非常复杂的。时间复杂度是logn*logn。

梁老师说,这是他们以前的写法,后来一次比赛,看到第一名的世界冠军用了另外一种不同的写法,他们感到非常不解,后来经过一番争论,确定了这种方法的准确性,就是我们学的。

 

    先深搜得出f[now][i]就是由当前的点,向上跳2^i步可以到达的地方。一开始f[now][0]为father。

    如何计算呢,假设要往上跳2^x的点,在dfs时,就利用倍增的思想,先跳到2^x-1的点后,从那个点再往上跳2^x-1个点。因为深搜由上往下,所以前面的点一定都已经算好了,所以能够求得出来。

    如图所示,求A和B的最近公共祖先。我们还是像以前一样往上跳。假设先跳了64步,结果发现跳过头了。如果是上一种方法,会通过up函数跳上去。但是这种方法选择不跳。

    于是,我们再看32步,跳,发现没有过头。跳过去以后在x点。那么应该再跳多少步呢?32步?不行,32步一条不就又跳到之前过头的地方了吗?所以我们跳的步数一定要小于32步,最大是31步。

    我们会发现1+2+4+8+16=31。所以说,无论是多少步,都可以到达。因此这种方法,不用往回跳,只要往前跳就可以了。条件是found[x]>found[A],我们的目标是,要跳到c点的后一个点,最后再输出c的祖先就可以了。所以不可以found[x]==found[A]。

    我尝试了一下可不可以达到c点然后直接输出now,事实证明好像不行。

牧场行走

题目描述

N头牛(2<=n<=1000)别人被标记为1到n,在同样被标记1到n的n块土地上吃草,第i头牛在第i块牧场吃草。 这n块土地被n-1条边连接。 奶牛可以在边上行走,第i条边连接第Ai,Bi块牧场,第i条边的长度是Li(1<=Li<=10000)。 这些边被安排成任意两头奶牛都可以通过这些边到达的情况,所以说这是一棵树。 这些奶牛是非常喜欢交际的,经常会去互相访问,他们想让你去帮助他们计算Q(1<=q<=1000)对奶牛之间的距离。

输入格式

*第一行:两个被空格隔开的整数:N和Q

*第二行到第n行:第i+1行有两个被空格隔开的整数:AI,BI,LI

*第n+1行到n+Q行:每一行有两个空格隔开的整数:P1,P2,表示两头奶牛的编号。

输出格式 1649.out

*第1行到第Q行:每行输出一个数,表示那两头奶牛之间的距离。

输入样例

4 2
2 1 2
4 3 2
1 4 3
1 2
3 2

输出样例

2
7

       这题需要算出两头奶牛之间的距离,利用我们学的求出最近公共祖先以后,其实他们俩的距离就只要算出A和B离祖先的距离相加就可以了。

#include<iostream>
#include<cstdio>
#include<cmath>
using namespace std;
int xx,yy,ll,cur=-1,n,q,v[1005],aa,bb;
int head[1005],dis[1005],times,found[1005],f[1005][15];
struct cow
{
	int ta,next,l;
}e[2005];
void add(int x,int y,int ll)
{
	cur++;
	e[cur].ta=y;
	e[cur].next=head[x];
	e[cur].l=ll;
	head[x]=cur;
}
void dfs(int now,int father)
{
	v[now]=1;
	found[now]=++times;
	f[now][0]=father;
	for(int i=1;i<=10;i++)
	{
		int x=f[now][i-1];
		f[now][i]=f[x][i-1];
	}	
int h=head[now];
	while(h!=-1)
	{

int t=e[h].ta;
		if(v[t]==0)
		{
			dis[t]=dis[now]+e[h].l;
			dfs(t,now);
		}
		h=e[h].next;
	}
}
int qw(int a,int b)
{
	if(a==b) return a;
	if(found[a]>found[b]) swap(a,b);
	int now=b;
	for(int i=10;i>=0;i--)
	{
		int x=f[now][i];
		if(found[x]>found[a]) now=x;
		
	}
	return f[now][0];
}
int main()
{
	freopen("1649.in","r",stdin);
	freopen("1649.out","w",stdout);
	cin>>n>>q;
	for(int i=1;i<=1005;i++) head[i]=-1;
	for(int i=1;i<n;i++)
	{
		cin>>xx>>yy>>ll;
		add(xx,yy,ll);
		add(yy,xx,ll);
	}
	dfs(1,1);
	while(q)
	{
		q--;
		cin>>aa>>bb;
		
		int c=qw(aa,bb);
		int ans=dis[aa]-dis[c]+dis[bb]-dis[c];
		cout<<ans<<endl;
	}
	return 0;
}

  

posted @ 2017-08-19 15:23  yiyiyizqy  阅读(159)  评论(0编辑  收藏  举报