现在的位置: 首页 > 综合 > 正文

poj-1330 Nearest Common Ancestors **

2012年06月02日 ⁄ 综合 ⁄ 共 1879字 ⁄ 字号 评论关闭
/*
* poj-1330.cpp
* LCA
*
* LCA入门题
*
* 没有用tarjan的离线算法, 用了个在线的, 时间复杂度O(n)-O(sqrt(n))
*
* height为树的高度
* 把树按层次分成sqrt(height)个段,每段sqrt(height)层。
*
* 对LCA(x, y)
* 先把x, y 导入到同一段, 由于最多sqrt(height)段, 所以O(sqrt(height))
* 再在同一段内, 按普通方法找到x, y的LCA, 由于每段sart(height)层, 所以O(sqrt(height))
* 故查询时间为 O(sqrt(height)) = O(sqrt(n))
*
* Created on: 2011-10-16
*/
#include <cstdio>
#include <cstring>
#include <cmath>
using namespace std;

const int maxN = 10000 + 10;

//secHeight每段的层数
int caseNum, n, root, height, secHeight;
//f[x]: x的父节点, layer[x]:x层数, p[x]:x在上一段中的祖先
int f[maxN], layer[maxN], stack[maxN], p[maxN];
bool isCreated[maxN];
//邻接表节点
struct SNode{
int key;
SNode *list;

SNode(int _key): key(_key), list(NULL) {}
};
SNode *tree[maxN];

//深搜计算layer[], 用栈实现
void calLayer(){
int top = 0, cur = root;
SNode *curNode;
layer[cur] = 0;

stack[top++] = cur;
while(top != 0){
cur = stack[--top];
curNode = tree[cur]->list;
while(curNode != NULL){
layer[curNode->key] = layer[cur] + 1;
stack[top++] = curNode->key;

curNode = curNode->list;
}
}
height = layer[cur];
}

//计算p数组
void dfs(int cur){
//第一段的节点 p = root
if(layer[cur] < secHeight)
p[cur] = root;
else if(layer[cur] % secHeight == 0)
p[cur] = f[cur];
else
p[cur] = p[f[cur]];

SNode *tmpNode = tree[cur]->list;
while(tmpNode != NULL){
dfs(tmpNode->key);

tmpNode = tmpNode->list;
}
}


//lca(x, y)
int LCA(int x, int y){
//让x和y到达同一段
while(p[x] != p[y]){
if(layer[x] > layer[y])
x = p[x];
else
y = p[y];
}

//按普通方法求lca
while(x != y){
if(layer[x] > layer[y])
x = f[x];
else
y = f[y];
}

return x;
}


int main(){
scanf("%d", &caseNum);
while(caseNum--){
scanf("%d", &n);

memset(isCreated, 0, sizeof(isCreated));
memset(f, -1, sizeof(f));
height = -1;

//输入,建树
int u, v;
SNode *tmpNode;
for(int i=1; i<n; i++){
scanf("%d %d", &u, &v);
if(!isCreated[u]){
tree[u] = new SNode(u);
isCreated[u] = 1;
}
if(!isCreated[v]){
tree[v] = new SNode(v);
isCreated[v] = 1;
}

tmpNode = new SNode(v);
tmpNode->list = tree[u]->list;
tree[u]->list = tmpNode;

f[v] = u;
}

//找到树根
for(int i=1; i<n; i++)
if(f[i] == -1){
root = i; break;
}

//计算各节点的层数
calLayer();
//每个分段的层数
secHeight = (int)sqrt(height + 0.0);

//计算p数组
dfs(root);

scanf("%d %d", &u, &v);
printf("%d\n", LCA(u, v));

}


return 0;
}

抱歉!评论已关闭.