在线的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; }
时间: 2024-10-11 21:25:52