标签:
这次使用离线算法来解决最近公共祖先的问题。
离线算法可以一遍 dfs 处理完所有的查询,因而需要把查询全部储存起来。
具体的 dfs 过程是:
所有节点最初标记为白色,第一次经过该节点时,将其染成灰色,第二次经过该节点时(即离开该节点时)将其染成黑色。
在 dfs 的某个状态下,白色代表未访问的节点,黑色代表已经访问完该节点为根整个子树,灰色代表正在访问该节点为根的子树。
可以在每个节点处查询与该节点相关的所有查询,每个查询对应有另一个节点X(可能是自身):
如果X是白色,说明还未访问到,信息不全,以后再处理;
如果X是灰色,说明当前节点是X子树中的元素,那么它们的最近公共祖先就是X;
如果X是黑色,可以寻找X的一个最近的灰色祖先节点Y,当前节点是Y的子树中的元素,X和当前节点的最近公共祖先就是Y。
如何查询与特定节点相关的所有查询呢?可以使用vector存下来。
如何寻找X的一个最近的灰色祖先节点Y呢?可以用并查集。
使用这种方法,每个查询实际上会被处理一次(白、黑/灰)或两次(灰、黑)。复杂度是 O(m) (m为查询量)的。
#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 root[MAX_HASH]; int color[MAX_HASH]; int query[MAX][2]; vector<int> i_query[MAX_HASH]; int ans[MAX]; int n; 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; } int get_root(int i) { return color[i] == 1 ? i : root[i] = get_root(root[i]); } void dfs(int root_idx) { color[root_idx] = 1; int len = i_query[root_idx].size(); for (int i = 0; i < len; i++) { int q_idx = i_query[root_idx][i]; int another = root_idx == query[q_idx][0] ? query[q_idx][1] : query[q_idx][0]; if (color[another] == 1) { ans[q_idx] = another; } else if (color[another] == 2 && ans[q_idx] == 0) { ans[q_idx] = get_root(another); } } int son_len = sons[root_idx].size(); for (int i = 0; i < son_len; i++) { dfs(sons[root_idx][i]); } color[root_idx] = 2; } 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); root[i2] = i1; start = i1; while (--n) { cin >> s1 >> s2; i1 = get_index(s1); i2 = get_index(s2); sons[i1].push_back(i2); root[i2] = i1; } cin >> n; for (int i = 0; i < n; i++) { cin >> s1 >> s2; i1 = get_index(s1); i2 = get_index(s2); query[i][0] = i1; query[i][1] = i2; i_query[i1].push_back(i); i_query[i2].push_back(i); } dfs(start); for (int i = 0; i < n; i++) { cout << names[ans[i]] << endl; } return 0; }
标签:
原文地址:http://www.cnblogs.com/xblade/p/4488835.html