LCA问题的离线处理Tarjan算法模版
Tarjan算法:
http://blog.csdn.net/smallacmer/article/details/7432625
1 //这个tarjan算法使用了并查集+dfs的操作。中间的那个并查集操作的作用,只是将已经查找过的节点捆成一个集合然后再指向一个公共的祖先。另外,如果要查询LCA(a,b),必须把(a,b)和(b,a)都加入邻接表。 2 // 3 //O(n+Q) 4 5 #include <iostream> 6 #include <cstdio> 7 #include <cstring> 8 #include <vector> 9 10 using namespace std; 11 12 #define MAXN 10001 13 14 int n,fa[MAXN]; 15 int rank[MAXN]; 16 int indegree[MAXN]; 17 int vis[MAXN]; 18 vector<int> hash[MAXN],Qes[MAXN]; 19 int ances[MAXN];//祖先 20 21 22 void init(int n) 23 { 24 for(int i=0;i<=n;i++) 25 { 26 fa[i]=i; 27 rank[i]=0; 28 indegree[i]=0; 29 vis[i]=0; 30 ances[i]=0; 31 hash[i].clear(); 32 Qes[i].clear(); 33 } 34 } 35 36 int find(int x) 37 { 38 if(x != fa[x]) 39 fa[x]=find(fa[x]); 40 return fa[x]; 41 } 42 43 void unio(int x,int y) 44 { 45 int fx=find(x),fy=find(y); 46 if(fx==fy) return ; 47 if(rank[fy]<rank[fx]) 48 fa[fy]=fx; 49 else 50 { 51 fa[fx]=fy; 52 if(rank[fx]==rank[fy]) 53 rank[fy]++; 54 } 55 } 56 57 void Tarjan(int u) 58 { 59 ances[u]=u; 60 int i,size = hash[u].size(); 61 for(i=0;i<size;i++) 62 { 63 Tarjan(hash[u][i]);//递归处理儿子 64 unio(u,hash[u][i]);//将儿子父亲合并,合并时会将儿子的父亲改为u 65 ances[find(u)]=u;//此时find(u)仍为u,即 66 } 67 vis[u]=1; 68 69 //查询 70 size = Qes[u].size(); 71 for(i=0;i<size;i++) 72 { 73 if(vis[Qes[u][i]]==1)//即查询的另一个结点开始已经访问过,当前的u在此回合访问。 74 { 75 printf("%d\n",ances[find(Qes[u][i])]);//由于递归,此时还是在u 76 return; 77 } 78 } 79 } 80 81 int main() 82 { 83 int t; 84 int i,j; 85 scanf("%d",&t); 86 while(t--) 87 { 88 scanf("%d",&n); 89 init(n); 90 int s,d; 91 for(i=1;i<=n-1;i++) 92 { 93 scanf("%d%d",&s,&d); 94 hash[s].push_back(d); 95 indegree[d]++; 96 } 97 scanf("%d%d",&s,&d); 98 // if(s==d)//如果需要计数的时候注意 99 // ans[d]++; 100 // else 101 // { 102 Qes[s].push_back(d); 103 Qes[d].push_back(s); 104 // } 105 for(j=1;j<=n;j++) 106 { 107 if(indegree[j]==0) 108 { 109 Tarjan(j); 110 break; 111 } 112 } 113 } 114 return 0; 115 }