裸的LCA离线算法,存下来当模板用吧。
思想就是,将所有的查询都先存起来,然后对树做一次dfs遍历,对每一次经过的节点进行染色,标记为未访问,正在访问,和已经访问完毕。可以很明显的发现如果当前点是一个查询的端点,那么如果另外一个端点正在访问,则当前点是另外一个端点的子节点,两者的LCA为另外一个端点,如果另外一个端点已经访问完了,那么就往上找最近的正在访问的端点,使得这两个点同时在这个端点的子树中。这里查找的时候用到了并查集路径压缩的思想。
#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 = 2e5 + 10;
int head[maxn], nxt[maxn << 1], v[maxn << 1], ecnt;
int headQ[maxn], nxtQ[maxn << 1], vQ[maxn << 1], idQ[maxn << 1], Qcnt;
int ans[maxn] , n, Q, fa[maxn], col[maxn];
bool hasfa[maxn];
map<string, int> mp;
map<int, string> smp;
char name1[maxn], name2[maxn];
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];
}
int getfa(int u) {
return u == fa[u] ? u : fa[u] = getfa(fa[u]);
}
void adde(int uu, int vv) {
v[ecnt] = vv; nxt[ecnt] = head[uu]; head[uu] = ecnt++;
}
void addQ(int uu, int vv, int nowid) {
vQ[Qcnt] = vv; nxtQ[Qcnt] = headQ[uu]; idQ[Qcnt] = nowid; headQ[uu] = Qcnt++;
}
void dfs(int now) {
//一开始把颜色填为灰色
col[now] = 1;
//看看是否有询问可以处理
for(int i = headQ[now]; ~i; i = nxtQ[i]) {
if(ans[idQ[i]] != 0) continue;
int nowv = vQ[i];
if(col[nowv] == 0) continue;
if(col[nowv] == 1) ans[idQ[i]] = nowv;
if(col[nowv] == 2) ans[idQ[i]] = getfa(nowv);
}
for(int i = head[now]; ~i; i = nxt[i]) {
dfs(v[i]);
//一个节点dfs完了之后,变颜色并且更新父节点
col[v[i]] = 2;
fa[v[i]] = now;
}
}
int main() {
memset(head, -1, sizeof(head));
memset(headQ, -1, sizeof(headQ));
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);
hasfa[b] = true;
}
int root;
scanf("%d", &Q);
for(int i = 1; i <= Q; i++) {
scanf("%s%s", name1, name2);
int a = getid(name1), b = getid(name2);
addQ(a, b, i); addQ(b, a, i);
}
n = mp.size();
for(int i = 1; i<= n; i++) if(!hasfa[i]) root = i;
for(int i = 1; i <= n; i++) fa[i] = i;
dfs(root);
for(int i = 1; i <= Q; i++) {
puts(smp[ans[i]].c_str());
}
return 0;
}