【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 }

 

转载于:https://www.cnblogs.com/Destiny-Gem/p/4025548.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值