POJ 1470(LCA)

博客给出了与LCA相关的代码,并附带提示信息,称其很容易。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Closest Common Ancestors

 

Description

  有一颗树,求给定两节点的公共祖先,最后输出每个节点当做祖先的次数。

Input

  输入文件包含多组测试数据。
  对于每组测试数据的第一行为一个整数n(n<=900),表示结点个数
  接下来n行,每行输入形式为k:(t)k1 k2…kt;第一个数字k,表示结点k;t表示k的儿子个数,k1 k2…kt分别表示k的儿子节点编号。
  第n+2行为一个整数表示询问最近公共祖先的结点对数
  接下来若干行来描述询问的结点,用一对括号括起来。

Output

  对于每组数据输出若干行,每行形式为“a:b”,表示结点a做公共祖先有b次,按照结点a的字典顺序输出。

Sample Input

5 5:(3) 1 4 2 1:(0) 4:(0) 2:(1) 3 3:(0) 6 (1,5) (1,4) (4,2) (2,3) (1,3) (4,3)

Sample Output

2:1 5:5

Hint

 

 

 

代码:

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
inline int read() {
	int data=0,w=1;
	char ch=0;
	while(ch!='-'&&(ch<'0'||ch>'9'))ch=getchar();
	if(ch=='-')w=-1,ch=getchar();
	while(ch>='0'&&ch<='9')data=data*10+ch-'0',ch=getchar();
	return data*w;
}
const int maxn=905;
struct point {
	int to,next;
};
point a[maxn*2];
int cnt=0,h[maxn];
void add(int x,int y) {
	a[++cnt].next=h[x];
	a[cnt].to=y;
	h[x]=cnt;
}
int f[maxn][21],hi[maxn];
void bfs(int x) {
	for(int i=1; i<=20; i++)f[x][i]=f[f[x][i-1]][i-1];
	for(int i=h[x]; i; i=a[i].next) {
		int v=a[i].to;
		hi[v]=hi[x]+1;
		bfs(v);
	}
}
int LCA(int x,int y) {
	if(hi[x]<hi[y])swap(x,y);
	for(int i=20; i>=0; i--)if(hi[f[x][i]]>=hi[y])x=f[x][i];
	if(x==y)return x;
	for(int i=20; i>=0; i--) {
		if(f[x][i]!=f[y][i]) {
			x=f[x][i];
			y=f[y][i];
		}
	}
	return f[x][0];
}
int ans[maxn];
int main() {
	int n,m,x,y;
	while(cin>>n) {
		memset(ans,0,sizeof(ans));
		memset(f,0,sizeof(f));
		memset(hi,0,sizeof(hi));
		memset(h,0,sizeof(h));
		cnt=0;
		for(int i=1; i<=n; i++) {
			y=read();
			m=read();
			for(int j=1; j<=m; j++) {
				x=read();
				add(y,x);
				f[x][0]=y;
			}
		}
		x=1;
		while(f[x][0]!=0)x=f[x][0];
		hi[x]=1;
		bfs(x);
		cin>>m;
		for(int i=1; i<=m; i++) {
			x=read();
			y=read();
			ans[LCA(x,y)]++;
		}
		for(int i=1; i<=n; i++)if(ans[i])cout<<i<<":"<<ans[i]<<endl;
	}
	return 0;
}

Hint

So easy!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值