您的位置:首页 > 其它

hihoCoder#1069 最近公共祖先·三

2015-04-01 09:58 393 查看
原题地址

根据提示用Spase Table做

将Tree先展成List,因为数组长度等于边数的2倍,树中边数等于节点数-1,所以List数组只要开2倍节点数大小即可

WA了几次,原来是查询的时候出现左边界大于右边界的情况,所以这种情况要颠倒一下

代码:

#include <iostream>
#include <vector>
#include <string>
#include <map>

using namespace std;

#define MAX_NODE 100005

int N, M;
map<string, int> a2i;
string i2a[MAX_NODE];
int traverse_path[MAX_NODE * 2];
int depth[MAX_NODE];
int st[MAX_NODE * 2][32]; // 保存的是节点编号
vector<int> child[MAX_NODE];
int last_position[MAX_NODE];
int path_length = 0;
int tree_size = 0;

void traverse(int r, int d) {
traverse_path[path_length++] = r;
depth[r] = d;
for (auto c : child[r]) {
traverse(c, d + 1);
traverse_path[path_length++] = r;
}
last_position[r] = path_length - 1;
}

void build() {
for (int i = 0; i < path_length; i++)
st[i][0] = traverse_path[i];

for (int j = 1; (1 << j) <= path_length; j++) {
for (int i = 0; i + (1 << j) <= path_length; i++) {
int a = st[i][j - 1];
int b = st[i + (1 << (j - 1))][j - 1];
st[i][j] = depth[a] < depth[b] ? a : b;
}
}
}

int query(int l, int r) {
if (l > r)
return query(r, l);
int len = r - l + 1;
int i = 0;
while ((1 << (i + 1)) <= len)
i++;
int a = st[l][i];
int b = st[r - (1 << i) + 1][i];
return depth[a] < depth[b] ? a : b;
}

int main() {
scanf("%d", &N);
for (int i = 0; i < N; i++) {
string a, b;
int ai, bi;
cin >> a >> b;
if (a2i.find(a) == a2i.end()) {
ai = a2i[a] = tree_size;
i2a[ai] = a;
tree_size++;
}
else
ai = a2i[a];
if (a2i.find(b) == a2i.end()) {
bi = a2i[b] = tree_size;
i2a[bi] = b;
tree_size++;
}
else
bi = a2i[b];
child[ai].push_back(bi);
}

traverse(0, 0);
build();

scanf("%d", &M);
while (M--) {
string a, b;
int ai, bi;
cin >> a >> b;
ai = a2i[a];
bi = a2i[b];
cout << i2a[query(last_position[ai], last_position[bi])] << endl;
}

return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: