【hihoCoder第十五周】最近公共祖先·二
老实说我没有读题,看见标题直接就写了,毕竟hiho上面都是裸的算法演练。
大概看了下输入输出,套着bin神的模板,做了个正反map映射,但是怎么都得不了满分。等这周结束后,找高人询问下trick。
若是有人找出了错误,或是发现代码中的不足,求指出。感激!~
以下是个人80分的代码。(之后献上两天之后的100分代码~_~)。
- #include <bits/stdc++.h>
- using namespace std;
- const int MAXN = ;
- int rmq[ * MAXN]; //rmq数组,就是欧拉序列对应的深度序列
- struct ST {
- int mm[ * MAXN];
- int dp[ * MAXN][]; //最小值对应的下标
- void init(int n) {
- mm[] = -;
- for(int i = ; i <= n; i++) {
- mm[i] = ((i & (i - )) == ) ? mm[i - ] + : mm[i - ];
- dp[i][] = i;
- }
- for(int j = ; j <= mm[n]; j++)
- for(int i = ; i + ( << j) - <= n; i++)
- dp[i][j] = rmq[dp[i][j - ]] <
- rmq[dp[i + ( << (j - ))][j - ]] ? dp[i][j - ] : dp[i + ( << (j - ))][j - ];
- }
- int query(int a, int b) { //查询[a,b]之间最小值的下标
- if(a > b)swap(a, b);
- int k = mm[b - a + ];
- return rmq[dp[a][k]] <=
- rmq[dp[b - ( << k) + ][k]] ? dp[a][k] : dp[b - ( << k) + ][k];
- }
- };
- //边的结构体定义
- struct Edge {
- int to, next;
- };
- Edge edge[MAXN * ];
- int tot, head[MAXN];
- int F[MAXN * ]; //欧拉序列,就是dfs遍历的顺序,长度为2*n-1,下标从1开始
- int P[MAXN];//P[i]表示点i在F中第一次出现的位置
- int cnt;
- ST st;
- map<string, int> Hash_zh;
- map<int, string> Hash_fa;
- void init() {
- tot = ;
- memset(head, -, sizeof(head));
- Hash_zh.clear();
- Hash_fa.clear();
- }
- void addedge(int u, int v) { //加边,无向边需要加两次
- edge[tot].to = v;
- edge[tot].next = head[u];
- head[u] = tot++;
- }
- void dfs(int u, int pre, int dep) {
- F[++cnt] = u;
- rmq[cnt] = dep;
- P[u] = cnt;
- for(int i = head[u]; i != -; i = edge[i].next) {
- int v = edge[i].to;
- if(v == pre)continue;
- dfs(v, u, dep + );
- F[++cnt] = u;
- rmq[cnt] = dep;
- }
- }
- void LCA_init(int root, int node_num) { //查询LCA前的初始化
- cnt = ;
- dfs(root, root, );
- st.init( * node_num - );
- }
- int query_lca(int u, int v) { //查询u,v的lca编号
- return F[st.query(P[u], P[v])];
- }
- bool flag[MAXN];
- int main() {
- int T, N;
- int u, v, cnt;
- string str_u, str_v;
- while(~scanf("%d", &N)) {
- init();
- cnt = ;
- memset(flag, false, sizeof(flag));
- for(int i = ; i <= N; i++) {
- //scanf("%d%d", &u, &v);
- cin >> str_u >> str_v;
- if (Hash_zh[str_u] == ) {
- Hash_fa[cnt] = str_u;
- Hash_zh[str_u] = cnt ++;
- }
- if (Hash_zh[str_v] == ) {
- Hash_fa[cnt] = str_v;
- Hash_zh[str_v] = cnt ++;
- }
- u = Hash_zh[str_u];
- v = Hash_zh[str_v];
- addedge(u, v);
- addedge(v, u);
- flag[v] = true;
- }
- int root;
- for(int i = ; i <= N; i++) {
- if(!flag[i]) {
- root = i;
- break;
- }
- }
- LCA_init(root, N);
- int query_n;
- scanf ("%d", &query_n);
- for (int i = ; i <= query_n; ++ i) {
- //scanf("%d%d", &u, &v);
- cin >> str_u >> str_v;
- if (str_u == str_v) {
- cout << str_u << endl;
- continue;
- }
- u = Hash_zh[str_u];
- v = Hash_zh[str_v];
- cout << Hash_fa[query_lca(u, v)] << endl;
- }
- }
- return ;
- }
前天晚上自己重新敲了一版,改用struct来存树,结果新代码直接就A掉了,但是还是不知道原来的问题。毕竟想法没错。仍旧是DFS + RMQ的ST。
- #include <bits/stdc++.h>
- using namespace std;
- #define MAXN 100005
- #define MAXM 105
- #define inf 0x7ffffff
- int n;
- struct Edge {
- int v, next;
- } edge[MAXN];
- int head[MAXN];
- int e;
- void addEdge(int u, int v) { //加边
- edge[e].v = v;
- edge[e].next = head[u];
- head[u] = e++;
- }
- int first[MAXN];//结点在搜索顺序数组中最先出现的位置(下标)
- int occur[MAXN << ]; //结点在出现的顺序数组重复的也要记录
- int depth[MAXN << ]; //结点在搜索树中的深度,与occur相对应
- int dp_min[MAXN << ][]; //dp_min[i][j] 表示从第i个位置开始的2^j个元素中的最小值的下标
- int m = ; //不断记录出现的下标
- void dfs(int u, int deep) {
- occur[++m] = u; //进入该点时进行记录
- depth[m] = deep;
- if(!first[u])
- first[u] = m;
- for(int i = head[u]; i + ; i = edge[i].next) {
- dfs(edge[i].v, deep + );
- occur[++m] = u; //访问子树返回也要标记
- depth[m] = deep;
- }
- }
- void init() {
- memset(head, -, sizeof(head));
- e = ;
- }
- void RMQ_init(int num) {
- for(int i = ; i <= num; i++)
- dp_min[i][] = i; //注意dp_min存的不是最小值,而是最小值的下标
- for(int j = ; j < ; j++)
- for(int i = ; i <= num; i++) {
- if(i + ( << j) - <= num) {
- dp_min[i][j] = depth[dp_min[i][j - ]] < depth[dp_min[i + ( << (j - ))][j - ]] ? dp_min[i][j - ] : dp_min[i + ( << (j - ))][j - ];
- }
- }
- }
- int RMQ_min(int a, int b) {
- int l = first[a], r = first[b]; //得到区间左右端点
- if(l > r) {
- int t = l;
- l = r;
- r = t;
- }
- int k = (int)(log(double(r - l + )) / log(2.0));
- int min_id = depth[dp_min[l][k]] < depth[dp_min[r - ( << k) + ][k]] ? dp_min[l][k] : dp_min[r - ( << k) + ][k]; //最小值下标
- return occur[min_id];//取得当前下标表示的结点
- }
- map<string, int> Hash_zh;
- map<int, string> Hash_fa;
- int main() {
- int t, a, b;
- init();
- m = ;
- memset(first, , sizeof(first));
- bool in[MAXN];//记录结点有无入度
- memset(in, false, sizeof(in));
- int u = , v = , cnt = ;
- string str_u, str_v;
- scanf("%d", &n);
- for(int i = ; i <= n; i++) { //注意此题只有n-1条边
- cin >> str_u >> str_v;
- if (Hash_zh[str_u] == ) {
- Hash_fa[cnt] = str_u;
- Hash_zh[str_u] = cnt ++;
- }
- if (Hash_zh[str_v] == ) {
- Hash_fa[cnt] = str_v;
- Hash_zh[str_v] = cnt ++;
- }
- u = Hash_zh[str_u];
- v = Hash_zh[str_v];
- addEdge(u, v); //u->v单向
- //in[v] = true;
- }
- dfs(, );
- RMQ_init(m);
- int op_n;
- scanf ("%d", &op_n);
- while (op_n --) {
- cin >> str_u >> str_v;
- if (str_u == str_v) {
- cout << str_u << endl;
- continue;
- }
- u = Hash_zh[str_u];
- v = Hash_zh[str_v];
- cout << Hash_fa[RMQ_min(u, v)] << endl;
- }
- return ;
- }
【hihoCoder第十五周】最近公共祖先·二的更多相关文章
- hihocoder 第二十五周 spfa 最短路
其实hihocoder里的题目目前大都是模板题啊-.- 这周的是SPFA,暑假的时候有看过SPFA,不过一直用的都是Dijkstra,感觉spfa要更加简洁一点~~,今天找了一份之前一直都看不太懂所以 ...
- 201871010105-曹玉中《面向对象程序设计(java)》第十五周学习总结
201871010105-曹玉中<面向对象程序设计(java)>第十五周学习总结 项目 内容 这个作业属于哪个过程 https://www.cnblogs.com/nwnu-daizh/ ...
- 第十四,十五周PTA作业
1.第十四周part1 7-3 #include<stdio.h> int main() { int n; scanf("%d",&n); int a[n]; ...
- 201771010134杨其菊《面向对象程序设计(java)》第十五周学习
第十五周学习总结 第一部分:理论知识 JAR文件: 应用程序首选项存储: Java Web Start JAR文件: 1.Java程序的打包:程序编译完成后,程序员将.class文件压缩打包为.jar ...
- 20145209刘一阳《JAVA程序设计》第十五周补充测试
第十五周补充测试 1.实验楼Linux中可以通过(ABC)查看用户登录情况. A .who B .who am i C .who mom likes D .who are you 2.在 Linux ...
- 2017面向对象程序设计(Java)第十五周学习总结
上周,老师要求同学们自学应用程序部署,并布置了相关的实验任务.此次实验的目的是掌握Java应用程序的打包操作:了解应用程序存储配置信息的两种方法: 了解Applet小应用程序的开发及应用方法:掌握基于 ...
- 201671010140. 2016-2017-2 《Java程序设计》java学习第十五周
java学习第十五周 Java的GUI界面设计,框架以及主要部件填充,归置,布局管理,在第十一章和第十二章进行了系统的学习,在这两章的知识奠基下,可以简单的构造一个GUI用户界面,在两周的学习后,可以 ...
- 201271050130-滕江南-《面向对象程序设计(java)》第十五周学习总结
201271050130-滕江南-<面向对象程序设计(java)>第十五周学习总结 博文正文开头格式:(2分) 项目 内容 这个作业属于哪个课程 https://www.cnblogs.c ...
- 201871010111-刘佳华《面向对象程序设计(java)》第十五周学习总结
201871010111-刘佳华<面向对象程序设计(java)>第十五周学习总结 实验十三 Swing图形界面组件(二) 实验时间 2019-12-6 第一部分:理论知识总结 5> ...
随机推荐
- DVP
债券结算方式是指在债券结算业务中,债券的所有权转移或权利质押与相应结算款项的交收这两者执行过程中的不同制约形式.中央债券簿记系统中所设计的结算方式有:纯券过户.见券付款.见款付券.券款对付(DVP)四 ...
- android开发常用组件(库)推荐
版本兼容:官方 support 全家桶 网络请求:Android-Async-Http.Retrofit.OkHttp.Volley图片加载:Glide 和 Universal-Image-Loade ...
- BLOG PLUGINS
文章分享按钮 (1)加网(JiaThis) (2)百度分享 文章关联推荐 每篇博文下面可以显示你博客中与该篇博文有些关联的几篇文章,也就是智能推荐,一方面可以增加你博文的曝光率和点击率,一方面也可以给 ...
- Nginx各个配置块功能详解
Nginx学习笔记-入门篇 nginx初探 ginx服务器是轻量级web服务器中广受好评的一款产品,常用功能有HTTP代理与反向代理(目前已支持七层与四层代理),负载均衡,web缓存. nginx配置 ...
- TTTAttributedLabel使用介绍(转)
TTTAttributedLabel 库地址 https://github.com/TTTAttributedLabel/TTTAttributedLabel 可以实现电话 地址 链接自动查找显示 ...
- java.util.Map.Entry接口
java.util.Map.Entry接口主要就是在遍历map的时候用到,给你个例子:package test;import java.util.*;import java.util.Map.Entr ...
- (转)ip地址,手机ip查询
页面地址:http://www.ip138.com/ 外链地址(实际主页面里面有)http://www.ip138.com/iplink.htm 外链地址里面的内容: <FORM METHOD= ...
- 监听键盘 防止输入时覆盖掉textfiled
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardwasChange:) name:U ...
- h5标签canvas关于getImageData跨域的问题
h5标签canvas关于getImageData跨域的问题 在学习h5的时候,canvas标签中getImageData()报错:security error! 具体代码如下(chrome浏览器): ...
- Spring MVC异常处理
Spring Mvc 中异常处理,一般有两种解决办法: 一.利用org.springframework.web.servlet.handler.SimpleMappingExceptionResolv ...