标签:str stdout r++ 跳过 int span mat logs stream
总结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; }
标签:str stdout r++ 跳过 int span mat logs stream
原文地址:http://www.cnblogs.com/yiyiyizqy/p/7396721.html