在线的LCA算法,dfs遍历整棵树,对于每个点出现的时候都插入到数组中,然后查询两个点的lca就是两个点在数组中最后出现位置间的dep值最小的点,就转化为链上的RMQ问题了。
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <map>
#include <set>
#include <bitset>
#include <queue>
#include <stack>
#include <string>
#include <iostream>
#include <cmath>
#include <climits>
using namespace std;
const int maxn = 1e5 + 10;
int head[maxn], nxt[maxn << 1], v[maxn << 1];
int rpos[maxn], n, Q, cnt, ecnt;
map<string, int> mp;
map<int, string> smp;
char name1[1024], name2[1024];
struct Node {
int dep, id;
bool operator < (const Node &x) const {
return dep < x.dep;
}
};
Node val[maxn << 1], minv[maxn << 1][30];
void adde(int uu, int vv) {
v[ecnt] = vv; nxt[ecnt] = head[uu]; head[uu] = ecnt++;
}
int getid(char *str) {
if(mp.count(str) == 0) {
int mpz = mp.size();
mp[str] = mpz + 1;
smp[mpz + 1] = str;
return mpz + 1;
}
return mp[str];
}
void dfs(int now, int fa, int dep) {
val[++cnt].dep = dep; val[cnt].id = now;
for(int i = head[now]; ~i; i = nxt[i]) if(v[i] != fa) {
dfs(v[i], now, dep + 1);
val[++cnt].dep = dep; val[cnt].id = now;
}
rpos[now] = cnt;
}
void initRMQ() {
for(int i = 1; i <= cnt; i++) {
minv[i][0] = val[i];
}
for(int j = 1; (1 << j) <= cnt; j++) {
for(int i = 1; i + (1 << j) - 1 <= cnt; i++) {
minv[i][j] = min(minv[i][j - 1], minv[i + (1 << (j - 1))][j - 1]);
}
}
}
Node query(int l, int r) {
int k = 0;
while((1 << (k + 1)) <= r - l + 1) k++;
return min(minv[l][k], minv[r - (1 << k) + 1][k]);
}
int main() {
memset(head, -1, sizeof(head));
scanf("%d", &n);
for(int i = 1; i <= n; i++) {
scanf("%s%s", name1, name2);
int a = getid(name1), b = getid(name2);
adde(a, b); adde(b, a);
}
dfs(1, -1, 0);
initRMQ();
scanf("%d", &Q);
while(Q--) {
scanf("%s%s", name1, name2);
int a = getid(name1), b = getid(name2);
a = rpos[a]; b = rpos[b];
if(a > b) swap(a, b);
Node ret = query(a, b);
puts(smp[ret.id].c_str());
}
return 0;
}