【hihoCoder第十五周】最近公共祖先·二

老实说我没有读题,看见标题直接就写了,毕竟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 }

 

你可能感兴趣的:(code)