老实说我没有读题,看见标题直接就写了,毕竟hiho上面都是裸的算法演练。
大概看了下输入输出,套着bin神的模板,做了个正反map映射,但是怎么都得不了满分。等这周结束后,找高人询问下trick。
若是有人找出了错误,或是发现代码中的不足,求指出。感激!~
以下是个人80分的代码。(之后献上两天之后的100分代码~_~)。
1 #include <bits/stdc++.h> 2 using namespace std; 3 4 const int MAXN = 1000010; 5 int rmq[2 * MAXN]; //rmq数组,就是欧拉序列对应的深度序列 6 7 struct ST { 8 int mm[2 * MAXN]; 9 int dp[2 * MAXN][20]; //最小值对应的下标 10 void init(int n) { 11 mm[0] = -1; 12 for(int i = 1; i <= n; i++) { 13 mm[i] = ((i & (i - 1)) == 0) ? mm[i - 1] + 1 : mm[i - 1]; 14 dp[i][0] = i; 15 } 16 for(int j = 1; j <= mm[n]; j++) 17 for(int i = 1; i + (1 << j) - 1 <= n; i++) 18 dp[i][j] = rmq[dp[i][j - 1]] < 19 rmq[dp[i + (1 << (j - 1))][j - 1]] ? dp[i][j - 1] : dp[i + (1 << (j - 1))][j - 1]; 20 } 21 int query(int a, int b) { //查询[a,b]之间最小值的下标 22 if(a > b)swap(a, b); 23 int k = mm[b - a + 1]; 24 return rmq[dp[a][k]] <= 25 rmq[dp[b - (1 << k) + 1][k]] ? dp[a][k] : dp[b - (1 << k) + 1][k]; 26 } 27 }; 28 //边的结构体定义 29 struct Edge { 30 int to, next; 31 }; 32 33 Edge edge[MAXN * 2]; 34 35 int tot, head[MAXN]; 36 int F[MAXN * 2]; //欧拉序列,就是dfs遍历的顺序,长度为2*n-1,下标从1开始 37 int P[MAXN];//P[i]表示点i在F中第一次出现的位置 38 int cnt; 39 ST st; 40 map<string, int> Hash_zh; 41 map<int, string> Hash_fa; 42 43 void init() { 44 tot = 0; 45 memset(head, -1, sizeof(head)); 46 Hash_zh.clear(); 47 Hash_fa.clear(); 48 } 49 50 void addedge(int u, int v) { //加边,无向边需要加两次 51 edge[tot].to = v; 52 edge[tot].next = head[u]; 53 head[u] = tot++; 54 } 55 56 void dfs(int u, int pre, int dep) { 57 F[++cnt] = u; 58 rmq[cnt] = dep; 59 P[u] = cnt; 60 for(int i = head[u]; i != -1; i = edge[i].next) { 61 int v = edge[i].to; 62 if(v == pre)continue; 63 dfs(v, u, dep + 1); 64 F[++cnt] = u; 65 rmq[cnt] = dep; 66 } 67 } 68 void LCA_init(int root, int node_num) { //查询LCA前的初始化 69 cnt = 0; 70 dfs(root, root, 0); 71 st.init(2 * node_num - 1); 72 } 73 74 int query_lca(int u, int v) { //查询u,v的lca编号 75 return F[st.query(P[u], P[v])]; 76 } 77 78 bool flag[MAXN]; 79 80 int main() { 81 int T, N; 82 int u, v, cnt; 83 string str_u, str_v; 84 while(~scanf("%d", &N)) { 85 init(); 86 cnt = 1; 87 memset(flag, false, sizeof(flag)); 88 for(int i = 1; i <= N; i++) { 89 //scanf("%d%d", &u, &v); 90 cin >> str_u >> str_v; 91 if (Hash_zh[str_u] == 0) { 92 Hash_fa[cnt] = str_u; 93 Hash_zh[str_u] = cnt ++; 94 } 95 if (Hash_zh[str_v] == 0) { 96 Hash_fa[cnt] = str_v; 97 Hash_zh[str_v] = cnt ++; 98 } 99 u = Hash_zh[str_u]; 100 v = Hash_zh[str_v]; 101 addedge(u, v); 102 addedge(v, u); 103 flag[v] = true; 104 } 105 int root; 106 for(int i = 1; i <= N; i++) { 107 if(!flag[i]) { 108 root = i; 109 break; 110 } 111 } 112 LCA_init(root, N); 113 int query_n; 114 scanf ("%d", &query_n); 115 for (int i = 1; i <= query_n; ++ i) { 116 //scanf("%d%d", &u, &v); 117 cin >> str_u >> str_v; 118 119 if (str_u == str_v) { 120 cout << str_u << endl; 121 continue; 122 } 123 124 u = Hash_zh[str_u]; 125 v = Hash_zh[str_v]; 126 cout << Hash_fa[query_lca(u, v)] << endl; 127 } 128 } 129 return 0; 130 }
前天晚上自己重新敲了一版,改用struct来存树,结果新代码直接就A掉了,但是还是不知道原来的问题。毕竟想法没错。仍旧是DFS + RMQ的ST。
1 #include <bits/stdc++.h> 2 3 using namespace std; 4 5 #define MAXN 100005 6 #define MAXM 105 7 #define inf 0x7ffffff 8 int n; 9 struct Edge { 10 int v, next; 11 } edge[MAXN]; 12 int head[MAXN]; 13 int e; 14 15 void addEdge(int u, int v) { //加边 16 edge[e].v = v; 17 edge[e].next = head[u]; 18 head[u] = e++; 19 } 20 int first[MAXN];//结点在搜索顺序数组中最先出现的位置(下标) 21 int occur[MAXN << 1]; //结点在出现的顺序数组重复的也要记录 22 int depth[MAXN << 1]; //结点在搜索树中的深度,与occur相对应 23 int dp_min[MAXN << 1][20]; //dp_min[i][j] 表示从第i个位置开始的2^j个元素中的最小值的下标 24 int m = 0; //不断记录出现的下标 25 26 void dfs(int u, int deep) { 27 occur[++m] = u; //进入该点时进行记录 28 depth[m] = deep; 29 if(!first[u]) 30 first[u] = m; 31 for(int i = head[u]; i + 1; i = edge[i].next) { 32 dfs(edge[i].v, deep + 1); 33 occur[++m] = u; //访问子树返回也要标记 34 depth[m] = deep; 35 } 36 } 37 void init() { 38 memset(head, -1, sizeof(head)); 39 e = 0; 40 } 41 42 void RMQ_init(int num) { 43 for(int i = 1; i <= num; i++) 44 dp_min[i][0] = i; //注意dp_min存的不是最小值,而是最小值的下标 45 for(int j = 1; j < 20; j++) 46 for(int i = 1; i <= num; i++) { 47 if(i + (1 << j) - 1 <= num) { 48 dp_min[i][j] = depth[dp_min[i][j - 1]] < depth[dp_min[i + (1 << (j - 1))][j - 1]] ? dp_min[i][j - 1] : dp_min[i + (1 << (j - 1))][j - 1]; 49 } 50 } 51 } 52 53 int RMQ_min(int a, int b) { 54 int l = first[a], r = first[b]; //得到区间左右端点 55 if(l > r) { 56 int t = l; 57 l = r; 58 r = t; 59 } 60 int k = (int)(log(double(r - l + 1)) / log(2.0)); 61 int min_id = depth[dp_min[l][k]] < depth[dp_min[r - (1 << k) + 1][k]] ? dp_min[l][k] : dp_min[r - (1 << k) + 1][k]; //最小值下标 62 return occur[min_id];//取得当前下标表示的结点 63 } 64 65 map<string, int> Hash_zh; 66 map<int, string> Hash_fa; 67 68 int main() { 69 int t, a, b; 70 init(); 71 m = 0; 72 memset(first, 0, sizeof(first)); 73 bool in[MAXN];//记录结点有无入度 74 memset(in, false, sizeof(in)); 75 int u = 0, v = 0, cnt = 1; 76 string str_u, str_v; 77 scanf("%d", &n); 78 for(int i = 1; i <= n; i++) { //注意此题只有n-1条边 79 cin >> str_u >> str_v; 80 if (Hash_zh[str_u] == 0) { 81 Hash_fa[cnt] = str_u; 82 Hash_zh[str_u] = cnt ++; 83 } 84 if (Hash_zh[str_v] == 0) { 85 Hash_fa[cnt] = str_v; 86 Hash_zh[str_v] = cnt ++; 87 } 88 u = Hash_zh[str_u]; 89 v = Hash_zh[str_v]; 90 addEdge(u, v); //u->v单向 91 //in[v] = true; 92 } 93 dfs(1, 0); 94 RMQ_init(m); 95 int op_n; 96 scanf ("%d", &op_n); 97 while (op_n --) { 98 cin >> str_u >> str_v; 99 if (str_u == str_v) { 100 cout << str_u << endl; 101 continue; 102 } 103 u = Hash_zh[str_u]; 104 v = Hash_zh[str_v]; 105 cout << Hash_fa[RMQ_min(u, v)] << endl; 106 } 107 108 return 0; 109 }