【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> ...
随机推荐
- hdu 4585 Shaolin(STL map)
Problem Description Shaolin temple is very famous for its Kongfu monks.A lot of young men go to Shao ...
- yii 分页 (ajax)
Controller:class MemberController extends Controller { public function actionmember_list() { ...
- muduo源代码分析--我对muduo的理解
分为几个模块 EventLoop.TcpServer.Acceptor.TcpConnection.Channel等 对于EventLoop来说: 他仅仅关注里面的主驱动力,EventLoop中仅仅关 ...
- Java可见性机制的原理
基本概念 可见性 当一个线程修改了共享变量时,另一个线程可以读取到这个修改后的值. 内存屏障(Memory Barriers) 处理器的一组指令,用于实现对内存操作的顺序限制. 缓冲行 CPU告诉缓存 ...
- linux文件解-压缩
常用: 解压tar.gz包 使用命令:tar -zxvf file.tar.gz -z 指有gzip的属性 -x 解开一个压缩文件的参数 -v解压过程中显示文件 -f放最后接filena ...
- mongo export import
mongoexport -h 127.0.0.1 -p 27170 -d dbs -c table -f field1,field2,field3 -q condition 路径.名称 mongoim ...
- Javascript高级程序设计读书笔记(第10章 DOM)
第10章 DOM 10.1 节点层次 每个节点都有一个nodeType属性,用于表明节点的类型.任何节点类型必是下面中的一个: Node.Element_NODE(1); NODE.ATTRIBUT ...
- FreeMarker辅助
/** * FreeMarker 辅助类 * @author Rubekid * */ public class FreeMarkerHelper { /** * 模板文件存放目录 */ privat ...
- MongoDB自学笔记2---1.2 初识MongoDB
1.2.1MongoDB简介 MongoDB是一个基于分布式文件存储的数据库.由C++语言编写.旨在为WEB应用提供可扩展的高性能数据存储解决方案. MongoDB是一个介于关系数据库和非关系数据库之 ...
- C程序设计语言练习题1-2
练习1-2 做个实验,当printf函数的参数字符串中包含\c(其中c是上面的转义字符串序列中未曾列出的某一个字符)时,观察一下会出现什么情况. 代码如下: #include <stdio.h& ...