根据提示用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 * ];
int depth[MAX_NODE];
int st[MAX_NODE * ][]; // 保存的是节点编号
vector<int> child[MAX_NODE];
int last_position[MAX_NODE];
int path_length = ;
int tree_size = ; void traverse(int r, int d) {
traverse_path[path_length++] = r;
depth[r] = d;
for (auto c : child[r]) {
traverse(c, d + );
traverse_path[path_length++] = r;
}
last_position[r] = path_length - ;
} void build() {
for (int i = ; i < path_length; i++)
st[i][] = traverse_path[i]; for (int j = ; ( << j) <= path_length; j++) {
for (int i = ; i + ( << j) <= path_length; i++) {
int a = st[i][j - ];
int b = st[i + ( << (j - ))][j - ];
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 + ;
int i = ;
while (( << (i + )) <= len)
i++;
int a = st[l][i];
int b = st[r - ( << i) + ][i];
return depth[a] < depth[b] ? a : b;
} int main() {
scanf("%d", &N);
for (int i = ; 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(, );
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 ;
}