hdu2586 LCA
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2586
思路:在求解最近公共祖先的问题上,用到的是Tarjan的思想,从根结点开始形成一棵深搜树,非常好的处理技巧就是在回溯到结点u的时候,u的子树已经遍历, 这时候才把u结点放入合并集合中,这样u结点和所有u的子树中的结点的最近公共祖先就是u了,u和还未遍历的所有u的兄弟结点及子树中的最近公共祖先就是 u的父亲结点。以此类推。这样我们在对树深度遍历的时候就很自然的将树中的结点分成若干的集合,两个集合中的所属不同集合的任意一对顶点的公共祖先都是 相同的,也就是说这两个集合的最近公共最先只有一个。对于每个集合而言可以用并查集来优化,时间复杂度就大大降低了,为O(n + q),n为总结点数,q为询问结点对数。
一般步骤:
//parent为并查集,FIND为并查集的查找操作
//QUERY为询问结点对集合
//TREE为基图有根树
Tarjan(u)
visit[u] =true
for each (u, v) in QUERY
if visit[v]
ans(u, v) = FIND(v)
for each (u, v) in TREE
if!visit[v]
Tarjan(v)
parent[v] = u
对于本道题的做法就是用dist数组记录任意节点到根节点的距离,然后最终的答案就是dist[u,v]=dist[u]+dist[v]-2*dist[LCA(u,v)]。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<algorithm> 5 #include<vector> 6 using namespace std; 7 #define MAXN 44444 8 9 struct Edge{ 10 int v,w,next; 11 }edge[MAXN*2]; 12 13 struct Node{ 14 int v,id; 15 Node(int _v,int _id):v(_v),id(_id){} 16 }; 17 18 int n,m,NE; 19 int head[MAXN]; 20 int dist[MAXN]; 21 bool mark[MAXN]; 22 int parent[MAXN]; 23 24 void Insert(int u,int v,int w) 25 { 26 edge[NE].v=v; 27 edge[NE].w=w; 28 edge[NE].next=head[u]; 29 head[u]=NE++; 30 } 31 32 int Find(int x){ 33 if(x==parent[x]){ 34 return parent[x]; 35 } 36 parent[x]=Find(parent[x]); 37 return parent[x]; 38 } 39 40 int num[MAXN][3]; 41 vector<vector<Node> >map; 42 void Tarjan(int u) 43 { 44 mark[u]=true; 45 //对于每一个询问 46 for(int i=0;i<map[u].size();i++){ 47 int v=map[u][i].v,id=map[u][i].id; 48 if(mark[v])num[id][2]=Find(v); 49 } 50 //对于树上的每一个节点 51 for(int i=head[u];i!=-1;i=edge[i].next){ 52 int v=edge[i].v,w=edge[i].w; 53 if(!mark[v]){ 54 dist[v]=dist[u]+w; 55 Tarjan(v); 56 parent[v]=u; 57 } 58 } 59 } 60 61 62 63 int main() 64 { 65 int _case,u,v,w; 66 scanf("%d",&_case); 67 while(_case--){ 68 scanf("%d%d",&n,&m); 69 NE=0; 70 memset(head,-1,sizeof(head)); 71 for(int i=1;i<n;i++){ 72 scanf("%d%d%d",&u,&v,&w); 73 Insert(u,v,w); 74 Insert(v,u,w); 75 } 76 map.clear(); 77 map.resize(n+4); 78 for(int i=1;i<=m;i++){ 79 scanf("%d%d",&u,&v); 80 num[i][0]=u; 81 num[i][1]=v; 82 map[u].push_back(Node(v,i)); 83 map[v].push_back(Node(u,i)); 84 } 85 for(int i=1;i<=n;i++)parent[i]=i; 86 memset(mark,false,sizeof(mark)); 87 dist[1]=0; 88 Tarjan(1); 89 for(int i=1;i<=m;i++){ 90 printf("%d\n",dist[num[i][0]]+dist[num[i][1]]-2*dist[num[i][2]]); 91 } 92 } 93 return 0; 94 }