POJ 1470/PKU 1470 Closest Common Ancestors __LCA

题目链接:http://poj.org/problem?id=1470


题目大意:开始让你构造一棵树,然后有Q对u,v,最后让你求出每对u,v的最近祖先的编号和次数。

输入一个Q,然后有Q组(u,v)每组中间还有空格,tab等。但,稍稍想一下就能发现,Q组uv一共有Q*2个字符串,所以我们讲稿Q*2组str就可以了scanf("%s",str),然后处理每组str求得u,v

/*/
/*lca离线算法
/*/

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<queue>
#include<ctime>
#include<cmath>
#include<climits>
#define sf scanf
#define pf printf
#define cls(a) memset(a,0,sizeof(a))
#define _cls(a) memset(a,-1,sizeof(a))


using namespace std;

struct Edge_t{
	int to,next;
}edge[3010];
int head[1010],et,qhead[1010],qt;//- -
int root[1010],ind[1010];//union & indgree
int anst[1010],color[1010];//ansector & color(visit)
//int res[400010];//respond
int num[1010];
vector<int>query[1010];

inline void adde(int u,int v){//add edge
	edge[et].to=v,edge[et].next=head[u],head[u]=et++;
}
inline int Find(int x){ return root[x]=root[x]==x?x:Find(root[x]);}

void Union(int u,int v){
	int ra=Find(u),rb=Find(v);
	root[rb]=ra;
}

void LCA(int u){//从根节点开始
	int v,e;
	anst[u]=u;
	for(e=head[u];e!=-1;e=edge[e].next){
		LCA((v=edge[e].to));
		Union(u,v);
		anst[Find(u)]=u;
	}
	color[u]=1;
	int s=query[u].size(),i=0;
	for(;i<s;++i)
		if(color[v=query[u][i]]){
			//res[query[e].pos]=
			num[anst[Find(v)]]++;
		}
}

int deal(char *s,int v){
	int i,ret=0;
	if(v){
		for(i=1;s[i];++i)
			ret*=10,ret+=s[i]-'0';
	}else{
		for(i=0;s[i+1];++i)
			ret*=10,ret+=s[i]-'0';
	}
	//pf("ret=%d\n",ret);
	return ret;
}

int main(){
	int n,m,i;
	int t,u,v;
	while(~sf("%d",&n)){
		for(qt=et=0,i=1;i<=n;++i)
			root[i]=i,head[i]=-1,ind[i]=0,anst[i]=-1,color[i]=0,query[i].clear(),num[i]=0;
		for(i=0;i<n;++i){
			sf("%d:(%d)",&u,&v);
			//pf("u=%d v=%d\n",u,v);
			while(v--){
				sf("%d",&m);
				adde(u,m);
				ind[m]++;
			}
		}
		int Q;
		char str[20];
		sf("%d",&Q);
		Q<<=1;//一共Q*2个字符串
		for(i=0;i<Q;++i){
			sf("%s",str);
			if(i&1) v=deal(str,0),query[u].push_back(v),query[v].push_back(u);
			else u=deal(str,1);//后面那个1表示u,0表示v
		}
		for(i=1;i<=n;++i)
			if(!ind[i]) break;
		LCA(i);
		for(i=1;i<=n;++i)
			if(num[i]) pf("%d:%d\n",i,num[i]);
	}
	return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值