POJ 1470(LCA离线算法)

/*
	LCA离线算法:
	void(int root){
		判断当前节点root是不是要查询集合组中一个点,如果是,那么查看组另一个点 ,如查被标记了,那么找这个点的根节点;就是他们两个的最近的公共祖先;
		
		标记root这个点;
		
		LCA(遍历 root下的所有结点) 
	}
	 
*/
#include <iostream> 
#include <fstream>
#include <cstring>
#include <vector>
using namespace std;
const int N = 1005;
vector<int> vec[N];
bool vis[N];
bool is_root[N];
int ans[N];
int father[N];
int ask[N][N];

int n, m, root;


void init_data(){
	for(int i=1; i<=n; ++i) for(int j=1; j<=n; ++j) ask[i][j] = 0;
	for(int i=1; i<=n; ++i){
		vis[i] = false;
		is_root[i] = true;
		father[i] = i;
		ans[i] = 0;
		vec[i].clear();
	}
}
int Find(int x){
	if(x == father[x]){
		return x;
	}else{
		return father[x] = Find(father[x]);
	}
}
void show_is_root(){
	for(int i=1; i<=n; ++i){
		if(is_root[i] == true){
			printf("%4d",1);
		}else{
			printf("%4d",0);
		}
	}
	printf("\n");
}
void LCA(int root){
	for(int i=1; i<=n; ++i){		
		if(vis[i] && ask[root][i]){
			ans[Find(i)] += ask[root][i];
		}
	}
	vis[root] = true;	
	for(int i=0; i<vec[root].size(); ++i){
		int temp = vec[root][i];
		LCA(temp);
		father[temp] = root;
	}
	
}

int main(){
//	freopen("a.txt", "r", stdin);	
	int a,b,c;	
	while( ~scanf("%d", &n) ){		
		init_data();
				
		for(int i=1; i<=n; ++i){
			scanf("%d:(%d)", &a, &b);
			for(int i=1; i<=b; ++i){
				scanf("%d", &c);				
				is_root[c] = false;
				vec[a].push_back(c);
			}
		}		
		for(int i=1; i<=n; ++i){
			if(is_root[i]){
				root = i;
				break;
			}
		}
		scanf("%d", &m);
		for(int i=1; i<=m; ++i){
			scanf(" (%d %d)", &a, &b);
			ask[a][b]++;
			ask[b][a]++;
		}
				
		LCA(root);
		
		for(int i=1; i<=n; ++i){
			if(ans[i]){
				printf("%d:%d\n", i, ans[i]);
			}
		}
	}	
	return 0;
}
发布了76 篇原创文章 · 获赞 0 · 访问量 7186

猜你喜欢

转载自blog.csdn.net/julicliy/article/details/81284846