这次是使用在线算法解决这个问题。
两个节点的最近公共祖先就是这两个节点的通路上深度最浅的那个节点。
可以通过一遍深搜把树转成数组:每次经过一个节点(无论是从父节点进入还是从子节点返回)时,把它放入数组。同时要记录每个节点在数组中最后一次出现的位置。
使用RMQ-ST算法预先计算2^k长度区间内深度最浅的节点编号。
对于每次询问,将其转换为两个区间段求解。
#include <iostream> #include <algorithm> #include <cstring> #include <vector> #define MAX 100005 #define MAX_HASH 200005 using namespace std; char names[MAX_HASH][50]; vector<int> sons[MAX_HASH]; int last_occurance[MAX_HASH]; int dpth[MAX_HASH]; int data[MAX * 2][25]; int idx, n, q; unsigned int BKDRHash(char *str) { unsigned int seed = 131; unsigned int hash = 0; while (*str) { hash = hash * seed + (*str++); } return (hash & 0x7FFFFFFF) % MAX_HASH; } int get_index(char *str) { int res = BKDRHash(str); while (strlen(names[res]) != 0 && strcmp(str, names[res])) { res++; if (res > MAX_HASH) res -= MAX_HASH; } if (strlen(names[res]) == 0) { strcpy(names[res], str); } return res; } void dfs(int root_idx, int depth) { dpth[root_idx] = depth; /*cout << names[root_idx] << depth << endl;*/ data[idx][0] = root_idx; last_occurance[root_idx] = idx; idx++; int sons_len = sons[root_idx].size(); for (int i = 0; i < sons_len; i++) { dfs(sons[root_idx][i], depth + 1); data[idx][0] = root_idx; last_occurance[root_idx] = idx; idx++; } } void pre_calc() { //for (int i = 0; i < idx; i++) { // cout << i << ":" << names[data[i][0]] << endl; //} int t = idx; int x = 0; while (t) { x++; t >>= 1; } x--; for (int i = 1; i <= x; i++) { for (int j = 0; j <= idx - (1 << i); j++) { data[j][i] = dpth[data[j][i - 1]] < dpth[data[j + (1 << (i - 1))][i - 1]] ? data[j][i - 1] : data[j + (1 << (i - 1))][i - 1]; //cout << j << ‘-‘ << j + (1 << i) - 1 <<‘:‘ << names[data[j][i]] << endl; } } } int main() { char s1[50], s2[50]; int i1, i2; int start; cin >> n; cin >> s1 >> s2; i1 = get_index(s1); i2 = get_index(s2); sons[i1].push_back(i2); start = i1; while (--n) { cin >> s1 >> s2; i1 = get_index(s1); i2 = get_index(s2); sons[i1].push_back(i2); } dfs(start, 0); pre_calc(); cin >> q; while(q--) { cin >> s1 >> s2; i1 = last_occurance[get_index(s1)]; i2 = last_occurance[get_index(s2)]; if (i1 > i2) { int t = i1; i1 = i2; i2 = t; } int len = i2 - i1 + 1; int x = 0; while (len) { x++; len >>= 1; } x--; len = 1 << x; cout << names[dpth[data[i1][x]] < dpth[data[i2 - len + 1][x]] ? data[i1][x] : data[i2 - len + 1][x]] << endl; } return 0; }
时间: 2024-10-26 22:01:09