根据提示用Spase Table做
将Tree先展成List,因为数组长度等于边数的2倍,树中边数等于节点数-1,所以List数组只要开2倍节点数大小即可
WA了几次,原来是查询的时候出现左边界大于右边界的情况,所以这种情况要颠倒一下
代码:
1 #include <iostream> 2 #include <vector> 3 #include <string> 4 #include <map> 5 6 using namespace std; 7 8 #define MAX_NODE 100005 9 10 int N, M; 11 map<string, int> a2i; 12 string i2a[MAX_NODE]; 13 int traverse_path[MAX_NODE * 2]; 14 int depth[MAX_NODE]; 15 int st[MAX_NODE * 2][32]; // 保存的是节点编号 16 vector<int> child[MAX_NODE]; 17 int last_position[MAX_NODE]; 18 int path_length = 0; 19 int tree_size = 0; 20 21 void traverse(int r, int d) { 22 traverse_path[path_length++] = r; 23 depth[r] = d; 24 for (auto c : child[r]) { 25 traverse(c, d + 1); 26 traverse_path[path_length++] = r; 27 } 28 last_position[r] = path_length - 1; 29 } 30 31 void build() { 32 for (int i = 0; i < path_length; i++) 33 st[i][0] = traverse_path[i]; 34 35 for (int j = 1; (1 << j) <= path_length; j++) { 36 for (int i = 0; i + (1 << j) <= path_length; i++) { 37 int a = st[i][j - 1]; 38 int b = st[i + (1 << (j - 1))][j - 1]; 39 st[i][j] = depth[a] < depth[b] ? a : b; 40 } 41 } 42 } 43 44 int query(int l, int r) { 45 if (l > r) 46 return query(r, l); 47 int len = r - l + 1; 48 int i = 0; 49 while ((1 << (i + 1)) <= len) 50 i++; 51 int a = st[l][i]; 52 int b = st[r - (1 << i) + 1][i]; 53 return depth[a] < depth[b] ? a : b; 54 } 55 56 int main() { 57 scanf("%d", &N); 58 for (int i = 0; i < N; i++) { 59 string a, b; 60 int ai, bi; 61 cin >> a >> b; 62 if (a2i.find(a) == a2i.end()) { 63 ai = a2i[a] = tree_size; 64 i2a[ai] = a; 65 tree_size++; 66 } 67 else 68 ai = a2i[a]; 69 if (a2i.find(b) == a2i.end()) { 70 bi = a2i[b] = tree_size; 71 i2a[bi] = b; 72 tree_size++; 73 } 74 else 75 bi = a2i[b]; 76 child[ai].push_back(bi); 77 } 78 79 traverse(0, 0); 80 build(); 81 82 scanf("%d", &M); 83 while (M--) { 84 string a, b; 85 int ai, bi; 86 cin >> a >> b; 87 ai = a2i[a]; 88 bi = a2i[b]; 89 cout << i2a[query(last_position[ai], last_position[bi])] << endl; 90 } 91 92 return 0; 93 }
时间: 2025-02-01 14:35:40