http://acm.hdu.edu.cn/showproblem.php?pid=2874
题意:给定有N个结点的森林和Q次询问,求任意给定的两个结点之间的距离。 N<=100000 , Q<=1000000
算法:LCA离线算法。所不同的是,这题并不是给你一颗树,而是一个森林,因此还需要用并查集将一颗树上的结点放到同一个集合中去,然后对每棵树用Tarjin算法求一次LCA,就可以得出结果了。
代码:
/*
LCA tarjin离线算法 + 并查集
*/
#include<stdio.h>
#include<string.h>
const int MAXN = 10010 ;
const int MAXM = 1000010 ;
int N, M , C ;
int par[MAXN] ;
struct Node{
int num ,next ;
int dis ;
}edge[MAXN*2] ;
int root[MAXN] ,cnt;
struct Node1{
int num;
int next ;
int f ;
}ee[2*MAXM] ;
int rr[MAXN],cc;
bool vis[MAXN] ,vis2[MAXN] ;
bool one[MAXN] ;
int ans[MAXM] ;
int dis[MAXN] ;
int father[MAXN] ;
int now_root ;
void Init(){
for(int i=1;i<=N;i++) par[i] = i ;
cnt = 0 ;
memset( root , -1 ,sizeof(root) );
cc = 0 ;
memset(rr , -1 ,sizeof(rr));
}
int find(int a){
if(a != par[a]){
par[a] = find( par[a] ) ;
}
return par[a] ;
}
void Union(int a, int b){
int fa = find(a) ;
int fb = find(b) ;
if(fa < fb){
par[fb] = fa ;
}
else if(fa > fb){
par[fa] = fb ;
}
}
void add(int a, int b ,int c){
edge[cnt].num = b ;
edge[cnt].dis = c ;
edge[cnt].next = root[a] ;
root[a] = cnt++ ;
}
void add2(int a, int b , int f){
ee[cc].num = b ;
ee[cc].f = f ;
ee[cc].next = rr[a] ;
rr[a] = cc++ ;
}
int find2(int a){
if(father[a] != a){
father[a] = find2( father[a] ) ;
}
return father[a] ;
}
void tarjin(int u){
vis[u] = 1 ;
for(int i=rr[u] ;i!=-1;i=ee[i].next){
int v = ee[i].num ;
int ff = ee[i].f ;
if(vis[v] == 1){
int n1 = find2(v);
ans[ff] = dis[u] + dis[v] - 2 * dis[n1] ;
}
}
for(int i=root[u] ;i!=-1;i=edge[i].next){
int v = edge[i].num ;
if(!vis[v]){
tarjin(v) ;
father[v] = u ;
}
}
}
void dfs(int u){
vis2[u] = 1 ;
for(int i=root[u] ;i!=-1;i=edge[i].next){
int v = edge[i].num ;
int dd = edge[i].dis ;
if(vis2[v] == 0){
dis[v] = dis[u] + dd ;
dfs(v);
}
}
}
int main(){
int i, j ,a ,b , c;
while(scanf("%d %d %d",&N,&M,&C) == 3){
Init() ;
for(i=0;i<M;i++){
scanf("%d %d %d",&a,&b,&c);
Union(a,b);
add(a,b,c); add(b,a,c) ;
}
memset(one , 0 , sizeof(one) );
for(i=1;i<=N;i++){
one[ find(i) ] = 1 ;
}
for(i=0;i<C;i++){
scanf("%d %d",&a,&b);
add2(a,b,i); add2(b,a,i);
}
memset( ans , -1 ,sizeof(ans) );
memset( vis2 , 0 ,sizeof(vis2) );
for(int i=1;i<=N;i++) father[i] = i ;
for(now_root=1;now_root<=N;now_root++){
if( one[now_root] == 0) continue ;
dis[now_root] = 0 ;
dfs(now_root);
memset(vis , 0 ,sizeof(vis) );
tarjin(now_root);
}
for(int i=0;i<C;i++){
if(ans[i] == -1){
printf("Not connected\n");
}
else{
printf("%d\n",ans[i]);
}
}
}
return 0 ;
}