[CODEVS4605]LCA

13 篇文章 0 订阅
6 篇文章 0 订阅
题目描述

顾名思义.给一棵有根树,以及一些询问,每次询问树上的2 个节点A、B,求它们的最近公共祖先.


输入描述
第一行一个整数N.接下来N 个数,第i 个数Fi 表示i 的父亲是Fi. 若Fi = 0,则i 为树根.

接下来一个整数M.接下来M 行,每行2 个整数A、B,询问节点(A xor LastAns)、(Bxor LastAns)的最近公共祖先. 其中LastAns 为上一个询问的答案,一开始LastAns = 0.


输出描述

对每一个询问输出相应的答案.


样例输入
10
0 1 2 3 2 4 2 5 4 9
10
3 9
2 7
7 8
1 1
0 6
6 11
6 3
10 7
2 15

7 7


样例输出
3
1
4
5
2
4
2
5
2

5


数据范围及提示

30% n,m≤1000

100% n,m≤100,000



题解:LCA裸题


倍增版:

#include<iostream>
#include<cstring>
#include<cstdlib>
#include<cstdio>
#include<cmath>
#include<algorithm>
using namespace std;
const int N=100010;
const int LOG=20;


int n, m, root;
void Getin( int &shu ) {
	char c; int f=1; shu=0;
	for( c=getchar(); c<'0' || c>'9'; c=getchar() ) if( c=='-' ) f=-1;
	for( ; c>='0' && c<='9'; c=getchar() ) shu=shu*10+c-'0';
	shu*=f;
}


int fir[N], ecnt;
struct node{ int e, next; }edge[N<<1];
void Link( int s, int e ) {
	edge[++ecnt].e=e; edge[ecnt].next=fir[s]; fir[s]=ecnt;
	edge[++ecnt].e=s; edge[ecnt].next=fir[e]; fir[e]=ecnt;
}


int fa[N][LOG+5], dep[N];
void DFS( int r, int f, int d ) {
	dep[r]=d;
	for( int i=fir[r]; i; i=edge[i].next )
		if( edge[i].e!=f ) {
			fa[edge[i].e][0]=r;
			DFS( edge[i].e, r, d+1 );
		}
}

void Build() {
	DFS( root, 0, 1 );
	for( int j=1; j<=LOG; j++ )
		for( int i=1; i<=n; i++ )
			fa[i][j]=fa[ fa[i][j-1] ][j-1];
}


int getk( int r ,int k ) {
	for( int i=0; i<=LOG; i++ )
		if( k&( 1<<i ) ) r=fa[r][i];
	return r;
}

int getd( int r, int d ) {
	return getk( r, dep[r]-d );
}


int p1, p2;
int LCA_Find() {
    if( dep[p1]<dep[p2] ) swap( p1, p2 ); 
    p1=getd( p1, dep[p2] );
	if( p1==p2 ) return p1;
	for( int i=LOG; i>=0; i-- )
		if( fa[p1][i]!=fa[p2][i] )
			p1=fa[p1][i], p2=fa[p2][i];
	return fa[p1][0];
}


int main() {
	Getin(n); 
	for( int i=1; i<=n; i++ ) {
		int f; Getin( f );
		if( !f ) { root=i; continue; }
		Link( f, i );
	}
	
	Build();
	
	Getin(m);
	
	int w=0;
	for( int i=1; i<=m; i++ ) {
		Getin( p1 ); Getin( p2 );
		p1^=w; p2^=w;
		w=LCA_Find();
		printf( "%d\n", w );
	}
	return 0;
}



链剖版:

#include<iostream>
#include<cstring>
#include<cstdlib>
#include<cstdio>
#include<cmath>
#include<algorithm>
using namespace std;
const int N=100010;


int n, m, root;
void Getin( int &shu ) {
	char c; int f=1; shu=0;
	for( c=getchar(); c<'0' || c>'9'; c=getchar() ) if( c=='-' ) f=-1;
	for( ; c>='0' && c<='9'; c=getchar() ) shu=shu*10+c-'0';
	shu*=f;
}


int fir[N], ecnt;
struct node{ int e, next; }edge[N];
void Link( int s, int e ) {
	edge[++ecnt].e=e; edge[ecnt].next=fir[s]; fir[s]=ecnt;
}


int fa[N], dep[N], siz[N], son[N];
void DFS1( int r, int d ) {
	dep[r]=d; siz[r]=1;
	for( int i=fir[r]; i; i=edge[i].next ) {
		DFS1( edge[i].e, d+1 );
		siz[r]+=siz[ edge[i].e ];
		if( siz[ edge[i].e ]>siz[ son[r] ] ) son[r]=edge[i].e;
	}
}

int top[N];
void DFS2( int r ) {
	if( son[r] ) top[ son[r] ]=top[r], DFS2( son[r] );
	for( int i=fir[r]; i; i=edge[i].next )
		if( edge[i].e!=son[r] ) {
			top[ edge[i].e ]=edge[i].e;
			DFS2( edge[i].e );
		}
}

int p1, p2;
int LCA() {
	while( top[p1]!=top[p2] ) {
		if( dep[ top[p1] ]>dep[ top[p2] ] ) p1=fa[ top[p1] ];
		else p2=fa[ top[p2] ];
	}
	return dep[p1]<dep[p2] ? p1 : p2;
}

int main() {
	Getin(n); 
	for( int i=1; i<=n; i++ ) {
		Getin( fa[i] );
		if( !fa[i] ) { root=i; continue; }
		Link( fa[i], i );
	}
	
	DFS1( root, 1 );
	top[root]=1; DFS2(root);
	
	Getin(m);
	int w=0;
	for( int i=1; i<=m; i++ ) {
		Getin( p1 ); Getin( p2 );
		p1^=w; p2^=w;
		w=LCA();
		printf( "%d\n", w );
	}
	return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值