HDU 4547 CD操作
传送门
没啥好说的。就是一个LCA。
不过就是有从根到子树里任意一个节点只需要一次操作,特判一下LCA是不是等于v。相等的话不用走。否则就是1次操作。
主要是想写一下倍增的板子。
倍增基于二进制。暴力求LCA算法是while循环一步一步往上走。但其实是不需要的。
因为一个点走到它的任意一个祖先都是确定的步数。都可用表示成二进制数。
$lca_{u,i}$代表从$u$向上走$2^{i}$步到哪一个节点
预处理出来。让$u$,$v$同深度,再向上走$x-1$步就好了($x$代表两$u, v$到它们LCA的深度差)
#include <cstdio> #include <algorithm> #include <cstring> #include <map> #include <string> #include <iostream> using namespace std;inline int read() {int x = 0, f = 1; char ch = getchar();while (ch < '0' || ch > '9') { if (ch == '-') f = -1; ch = getchar(); }while (ch >= '0' && ch <= '9') { x = x * 10 + ch - 48; ch = getchar(); }return x * f; } const int N = 1e5 + 10; struct Edge { int v, next; } edge[N]; int n, m, cnt, head[N], fa[N], degree[N], lca[N][17], dep[N]; bool vis[N]; map<string, int> mp; int tol;inline void init() { memset(head, 0, sizeof(head));memset(fa, 0, sizeof(fa));memset(vis, 0, sizeof(vis));memset(degree, 0, sizeof(degree));memset(lca, 0, sizeof(lca));cnt = tol = 0;mp.clear(); }inline void addedge(int u, int v) {edge[++cnt].v = v; edge[cnt].next = head[u]; head[u] = cnt; }int index(string s) {if (mp.find(s) != mp.end()) return mp[s];return mp[s] = ++tol; }void dfs(int u) {vis[u] = 1;lca[u][0] = fa[u];for (int i = 1; i <= 16; i++) lca[u][i] = lca[lca[u][i-1]][i-1];for (int i = head[u]; i; i = edge[i].next) {int v = edge[i].v;if (vis[v]) continue;dep[v] = dep[u] + 1;fa[v] = u;dfs(v); } }int Lca(int u, int v) {if (dep[u] < dep[v]) swap(u, v);for (int i = 16; i >= 0; i--) if (dep[lca[u][i]] >= dep[v]) u = lca[u][i];if (u == v) return u;for (int i = 16; i >= 0; i--) if (lca[u][i] != lca[v][i]) u = lca[u][i], v = lca[v][i];return lca[u][0]; }int main() {int T = read();while (T--) {init();n = read(); m = read();for (int i = 0; i < n - 1; i++) {string a, b;cin >> a >> b;int u = index(a), v = index(b);addedge(v, u);degree[u]++;}int root = 0;for (int i = 1; i <= n; i++) if (!degree[i]) { root = i; break; }fa[root] = root;dfs(root);while (m--) {string a, b;cin >> a >> b;int u = index(a), v = index(b);int r = Lca(u, v);printf("%d\n", dep[u] - dep[r] + (v == r ? 0 : 1));}} return 0; }
View Code
交了之后发现跑了两秒多
然后写了发tarjan的 跑了1秒多 果然 tarjan的时间复杂度还是最优的
#include <cstdio> #include <algorithm> #include <cstring> #include <map> #include <string> #include <iostream> using namespace std;inline int read() {int x = 0, f = 1; char ch = getchar();while (ch < '0' || ch > '9') { if (ch == '-') f = -1; ch = getchar(); }while (ch >= '0' && ch <= '9') { x = x * 10 + ch - 48; ch = getchar(); }return x * f; } const int N = 1e5 + 10; struct Edge { int v, next; } edge[N]; int cnt, head[N]; inline void addedge(int u, int v) {edge[++cnt].v = v; edge[cnt].next = head[u]; head[u] = cnt; } struct Qedge { int v, next, num; } qedge[N * 2]; int qcnt, qhead[N]; inline void addqedge(int u, int v, int num) {qedge[++qcnt].v = v;qedge[qcnt].next = qhead[u];qhead[u] = qcnt;qedge[qcnt].num = num; } int n, m, fa[N], degree[N], dep[N]; int ans[N]; bool vis[N]; map<string, int> mp; int tol;inline void init() { memset(head, 0, sizeof(head));memset(qhead, 0, sizeof(qhead));memset(fa, 0, sizeof(fa));memset(vis, 0, sizeof(vis));memset(degree, 0, sizeof(degree));memset(dep, 0, sizeof(dep));memset(ans, 0, sizeof(ans));cnt = qcnt = tol = 0;mp.clear(); }int getfa(int x) { return x == fa[x] ? x : fa[x] = getfa(fa[x]); }int index(string s) {if (mp.find(s) != mp.end()) return mp[s];return mp[s] = ++tol; }void dfs(int u) {fa[u] = u;vis[u] = 1;for (int i = head[u]; i; i = edge[i].next) {int v = edge[i].v;if (vis[v]) continue;dep[v] = dep[u] + 1;dfs(v);fa[v] = u;}for (int i = qhead[u]; i; i = qedge[i].next) {int v = qedge[i].v;if (vis[v]) {ans[qedge[i].num] = getfa(v);}} }int main() {int T = read();while (T--) {init();n = read(); m = read();for (int i = 0; i < n - 1; i++) {string a, b;cin >> a >> b;int u = index(a), v = index(b);addedge(v, u);degree[u]++;}int root = 0;for (int i = 1; i <= n; i++) if (!degree[i]) { root = i; break; }for (int i = 1; i <= m; i++) {string a, b;cin >> a >> b;int u = index(a), v = index(b);addqedge(u, v, i);addqedge(v, u, i);}dep[root] = 0;dfs(root);for (int i = 1; i <= m; i++) {int u = qedge[2 * i].v, v = qedge[2 * i - 1].v;printf("%d\n", dep[u] - dep[ans[i]] + (ans[i] == v ? 0 : 1));}}return 0; }
View Code
转载于:https://www.cnblogs.com/Mrzdtz220/p/10781335.html
HDU 4547 CD操作相关推荐
- 【HDU 4547 CD操作】LCA问题 Tarjan算法
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4547 题意:模拟DOS下的cd命令,给出n个节点的目录树以及m次查询,每个查询包含一个当前目录cur和 ...
- HDU - 4547 CD操作(LCA模板)
题目链接:点击查看 题目大意:给出一个层层嵌套的树状结构,可以从某一点通过一个操作直接到达任意一个子节点的位置,但如果要从某个节点到达其祖先节点需要一层一层往上爬,问若要从节点A到达节点B,需要多少步 ...
- hdu 4547(LCA+Tarjan)
解题思路:很明显的LCA问题,用Tarjan离线算法即可.这里输入的可能是字符串,所以直接用map保存.此外,根据题意,这里需要稍稍有点变化,因为cd:a\b\c...这里是一步即可完成,所以在查询a ...
- hdu 2034 - 集合操作
题意:集合A,B,计算集合差A-B(求只在集合A内的数) 解法: 选用STL内的集合set 1.建立set 2.关于集合的遍历,固定的格式: 用容器的iterator访问所有数据. 3.相应的用*it ...
- java调用cd传输_Java调用Linux命令(cd的处理)
一.Java调用Linux系统的命令非常简单 这是一个非常常用的调用方法示例: 1 publicString executeLinuxCmd(String cmd) {2 System.out.pri ...
- java 执行cd_Java调用Linux命令(cd的处理)
一.Java调用Linux系统的命令非常简单 这是一个非常常用的调用方法示例:public String executeLinuxCmd(String cmd) { System.out.printl ...
- 【Azure + Core】实现CI/CD(一)构建镜像并推送仓库
(海上生明月,天涯共此时) 今天是农历八月十六,大家中秋节快乐! 放了三天假,和家人整理下屋子,打扫下卫生,闲着无聊就研究点儿新东西.最近一直再看DevOps相关的内容,自从开始学习Docker以来, ...
- 【壹个小技巧】一看就会的CI/CD :Github Actions
什么是 CI/CD? 我这里先不说概念,先说一个平时开发的场景问题: 我们平时开发一个项目,经常会遇到这些"小"问题: 就是如何保证自己的项目是正确的,至少拿给别人的时候,可以编译 ...
- linux终端中出现 cd: OLDPWD 未设定 的提示
是因为开始刚打开终端,第一次操作cd命令的原因. cd - 的作用是进入上一次cd操作的目录,而此时刚打开终端,第一次执行cd命令,本次命令是第一次cd的目录,没有上一次的目录. 看个例子:
最新文章
- 2-Runtime objc_object objc_class
- 多态amp;nbsp;OC——第十天
- 线上环境部署MongoDB的官方建议
- Java学习笔记_数组
- java 图片阴影_Java 为 PPT 中的图形添加阴影效果
- 对 app_offline.htm 的几点错误认识
- Mac 连过的 WiFi 怎么查密码?看这→
- 北京市延庆区谷歌卫星地图下载
- Robo3T操作MongoDB数据库常用命令
- 【软件测试基础理论知识】1.1.常见的软件开发模型之———瀑布模型、原型模型、快速原型模型
- 对于目标文件系统,文件过大怎么办
- 整车CAN网络拓扑图
- 同步机制应遵循的准则
- 杀毒软件工作原理 及 现在主要杀毒技术
- CSDN 下载 版块问题解决日志
- labview:一个采集数据的小程序
- 星之卡比机器人汉化_星之卡比:机械星球
- 西门子触摸屏数据历史数据记录_西门子触摸屏mp277历史数据丢失(免费技术支持)...
- 微信小程序_文档_08_组件_媒体组件_地图_画布_开放能力
- 程序员一定要打造一个专业的家庭开发工作站