裸的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; }