您的位置:首页 > 其它

poj--1330 Nearest Common Ancestors(LCA/Tarjan)

2016-09-22 21:21 417 查看
Nearest Common Ancestors

题解

求有根树中u和v的最近公共祖先。

初次练习LCA Tarjan.

参考

LCA/Tarjan是基于dfs+并查集的离线算法,即需要记录下所有的询问后再应答。

LCA(u, v)是根至u的路径上到v最近的节点。

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <vector>
using namespace std;

const int maxn = 10000 + 5;
const int maxq = 5;

int t, n, totE, totQ;
int p[maxn];
int head[maxn];
struct Node{ int to, next, lca; } edge[maxn * 2];   //graph
int qhead[maxn];
Node qedge[maxq];   // query

void init(){
totE = totQ = 0;
memset(head, -1, sizeof(head));
memset(qhead, -1, sizeof(qhead));
memset(p, -1, sizeof(p));
}
int find(int x) { return x == p[x] ? x : p[x] = find(p[x]); }

void addEdge(int u, int v){
edge[totE].to = v;
edge[totE].next = head[u];
head[u] = totE++;
}
// 离线处理需要记录所有的询问
void addQuery(int u, int v){
qedge[totQ].to = v;
qedge[totQ].next = qhead[u];
qhead[u] = totQ++;
}

void LCA_Tarjan(int u){
p[u] = u;
for(int i = head[u]; ~i; i = edge[i].next){
int v = edge[i].to;
if(p[v] == -1){ // 若v还没访问
LCA_Tarjan(v);
p[v] = u;   // 合并
}
}
// 处理和u有关的查询(u, v), 如果v访问过,LCA就是v坐在集合的代表元素,即find(v)
for(int i = qhead[u]; ~i; i = qedge[i].next){
int v = qedge[i].to;
if(p[v] != -1){ // v已经访问过
qedge[i].lca = find(v);
qedge[i^1].lca = qedge[i].lca;
}
}
}

int main(){
#ifdef EXMY
freopen("data.in", "r", stdin);
#endif // EXMY
scanf("%d", &t);
while(t--){
scanf("%d", &n);
init();
int root, u, v;
for(int i = 0; i < n - 1; ++i){
scanf("%d %d", &u, &v);
if(!i) root = u;    //记录根节点
addEdge(u, v);
addEdge(v, u);
}
// query
scanf("%d %d", &u, &v);
addQuery(u, v);
addQuery(v, u);

LCA_Tarjan(root);
printf("%d\n", qedge[0].lca);
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  poj 图论 LCA Tarjan