poj 1330 tarjan lca
http://poj.org/problem?id=1330
tarjan 求解lca主要利用并差集的想法:首先遍历树,从叶子节点开始向上合并成一棵棵的子树,然后子树并子树,就成了一棵树了。
查找是在合并的时候进行的,exp:u是s,t的lca,先从u节点进入s,把s并到u下面,然后发现t没有被访问,退到u,再进入t,同样把t并到u下面,发现s被访问过了,那么s的lca也就是s,t的lca了,也就是并差集里的f[s]。当然,f[s]会变的:假设当前f[s] = u; f[u] = u; 当u并到v的时候,也就是f[u]=v; 相应的f[s] = v。这也就是tarjan求解lca的关键方法。
这个题裸lca,模板直接上。

#include<stdio.h> #include<string.h> #include<iostream> #include<vector> #include<algorithm> using namespace std; const int maxn = 10005; struct nd { int to,next; }edge[maxn*2]; vector<int>qes[maxn]; int f[maxn],in[maxn],vis[maxn],ans[maxn],ecnt,head[maxn],ok; void add(int s,int t) { edge[ecnt].to = t; edge[ecnt].next = head[s]; head[s] = ecnt++; } int Find(int x) { if(x!=f[x]) f[x] = Find(f[x]); return f[x]; } void LCA(int u) { int i; if(ok)return; ans[u] = u; for(i = head[u]; i!=-1; i=edge[i].next) { LCA(edge[i].to); int x = Find(u); int y = Find(edge[i].to); if(x!=y) f[x] = y; ans[Find(u)] = u; } vis[u] = 1; for(i = 0; i < qes[u].size(); ++ i) { if(vis[qes[u][i]]) { ok = 1; printf("%d\n",ans[Find(qes[u][i])]); return ; } } } int main() { int cas,n,i,s,t; scanf("%d",&cas); while(cas--) { scanf("%d",&n); for(i = 0; i <= n; ++ i) f[i] = i; memset(vis,0,sizeof(vis)); memset(in,0,sizeof(in)); memset(ans,0,sizeof(ans)); memset(head,-1,sizeof(head)); ecnt = 0; for(i = 1; i < n; ++ i) { scanf("%d %d",&s,&t); add(s,t); in[t]++; } scanf("%d%d",&t,&s); qes[t].push_back(s); qes[s].push_back(t); ok = 0; for(int i = 1; i <= n; ++ i) if(!in[i]) { LCA(i); break; } qes[t].clear(); qes[s].clear(); }return 0; }