传送门

没啥好说的。就是一个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 = , f = ; char ch = getchar();
while (ch < '' || ch > '') { if (ch == '-') f = -; ch = getchar(); }
while (ch >= '' && ch <= '') { x = x * + ch - ; ch = getchar(); }
return x * f;
}
const int N = 1e5 + ;
struct Edge { int v, next; } edge[N];
int n, m, cnt, head[N], fa[N], degree[N], lca[N][], dep[N];
bool vis[N];
map<string, int> mp;
int tol; inline void init() {
memset(head, , sizeof(head));
memset(fa, , sizeof(fa));
memset(vis, , sizeof(vis));
memset(degree, , sizeof(degree));
memset(lca, , sizeof(lca));
cnt = tol = ;
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] = ;
lca[u][] = fa[u];
for (int i = ; i <= ; i++) lca[u][i] = lca[lca[u][i-]][i-];
for (int i = head[u]; i; i = edge[i].next) {
int v = edge[i].v;
if (vis[v]) continue;
dep[v] = dep[u] + ;
fa[v] = u;
dfs(v);
}
} int Lca(int u, int v) {
if (dep[u] < dep[v]) swap(u, v);
for (int i = ; i >= ; i--) if (dep[lca[u][i]] >= dep[v]) u = lca[u][i];
if (u == v) return u;
for (int i = ; i >= ; i--) if (lca[u][i] != lca[v][i]) u = lca[u][i], v = lca[v][i];
return lca[u][];
} int main() {
int T = read();
while (T--) {
init();
n = read(); m = read();
for (int i = ; i < n - ; i++) {
string a, b;
cin >> a >> b;
int u = index(a), v = index(b);
addedge(v, u);
degree[u]++;
}
int root = ;
for (int i = ; 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 ? : ));
}
}
return ;
}

交了之后发现跑了两秒多

然后写了发tarjan的 跑了1秒多 果然 tarjan的时间复杂度还是最优的

#include <cstdio>
#include <algorithm>
#include <cstring>
#include <map>
#include <string>
#include <iostream>
using namespace std; inline int read() {
int x = , f = ; char ch = getchar();
while (ch < '' || ch > '') { if (ch == '-') f = -; ch = getchar(); }
while (ch >= '' && ch <= '') { x = x * + ch - ; ch = getchar(); }
return x * f;
}
const int N = 1e5 + ;
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 * ];
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, , sizeof(head));
memset(qhead, , sizeof(qhead));
memset(fa, , sizeof(fa));
memset(vis, , sizeof(vis));
memset(degree, , sizeof(degree));
memset(dep, , sizeof(dep));
memset(ans, , sizeof(ans));
cnt = qcnt = tol = ;
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] = ;
for (int i = head[u]; i; i = edge[i].next) {
int v = edge[i].v;
if (vis[v]) continue;
dep[v] = dep[u] + ;
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 = ; i < n - ; i++) {
string a, b;
cin >> a >> b;
int u = index(a), v = index(b);
addedge(v, u);
degree[u]++;
}
int root = ;
for (int i = ; i <= n; i++) if (!degree[i]) { root = i; break; }
for (int i = ; 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] = ;
dfs(root);
for (int i = ; i <= m; i++) {
int u = qedge[ * i].v, v = qedge[ * i - ].v;
printf("%d\n", dep[u] - dep[ans[i]] + (ans[i] == v ? : ));
}
}
return ;
}

HDU 4547 CD操作的更多相关文章

  1. HDU 4547 CD操作 (LCA最近公共祖先Tarjan模版)

    CD操作 倍增法  https://i.cnblogs.com/EditPosts.aspx?postid=8605845 Time Limit : 10000/5000ms (Java/Other) ...

  2. 【HDU 4547 CD操作】LCA问题 Tarjan算法

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4547 题意:模拟DOS下的cd命令,给出n个节点的目录树以及m次查询,每个查询包含一个当前目录cur和 ...

  3. hdu 4547 LCA **

    题意:在Windows下我们可以通过cmd运行DOS的部分功能,其中CD是一条很有意思的命令,通过CD操作,我们可以改变当前目录. 这里我们简化一下问题,假设只有一个根目录,CD操作也只有两种方式: ...

  4. lca讲解 && 例题 HDU - 4547

    一. 最普通的找树中两个点x,y最近公共祖先: 在进行lca之前我们要先对这一颗树中的每一个点进行一个编号,像下图一样.这个编号就是tarjan算法中的dfn[]数组 这样的话我们可以在跑tarjan ...

  5. 【HDU 4547】 CD操作

    [题目链接] 点击打开链接 [算法] 分四种情况讨论 : 1. 当前目录和目标目录是同一目录,不需要变换,答案为0 2. 当前目录是目标目录的祖先,答案为当前目录的深度 - 目标目录的深度 3. 当前 ...

  6. hdu 4547(LCA)

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4547 思路:这题的本质还是LCA问题,但是需要注意的地方有: 1.如果Q中u,v的lca为u,那么只需 ...

  7. hdu 5071 vector操作恶心模拟

    http://acm.hdu.edu.cn/showproblem.php?pid=5071 对于每一个窗口,有两个属性:优先级+说过的单词数,支持8个操作:新建窗口,关闭窗口并输出信息,聊天(置顶窗 ...

  8. 基于docker搭建Jenkins+Gitlab+Harbor+Rancher架构实现CI/CD操作

    一.各个组件的功能描述: Docker 是一个开源的应用容器引擎. Jenkis 是一个开源自动化服务器. (1).负责监控gitlab代码.gitlab中配置文件的变动: (2).负责执行镜像文件的 ...

  9. hdu 2034 - 集合操作

    题意:集合A,B,计算集合差A-B(求只在集合A内的数) 解法: 选用STL内的集合set 1.建立set 1: #include<set> 2:   3: set<int> ...

随机推荐

  1. Python:黑板课爬虫闯关第一关

    近日发现了[黑板课爬虫闯关]这个神奇的网页,练手爬虫非常的合适 地址:http://www.heibanke.com/lesson/crawler_ex00/ 第一关非常的简单 get 请求网址,在响 ...

  2. SpringBoot技术栈搭建个人博客【前台开发/项目总结】

    前言:写前台真的是我不擅长的东西...所以学习和写了很久很久...前台页面大概开发了两天半就开发好了,采用的静态的html和bootstrap来写,写后台的时候纠结住了...怎么说呢,写页面真的是头疼 ...

  3. 关于ApiCloud的Superwebview在androidstudio中集成微信支付模块,提示模块未绑定的问题

    前两天ApiCloud项目集成了微信支付模块,android端今天也将ApiCloud官方的uzWxPay.jar集成了.在编译玩测试的时候提示wxPay模块为绑定!我的项目是使用ApiCloud推出 ...

  4. 从零开始搭建Prometheus自动监控报警系统

    从零搭建Prometheus监控报警系统 什么是Prometheus? Prometheus是由SoundCloud开发的开源监控报警系统和时序列数据库(TSDB).Prometheus使用Go语言开 ...

  5. Centos7+LVS-DR+keepalived实验(包含sorry-server、日志、及HTTP-GET的健康检测)

    目录检索 一.简介 1.lvs-dr原理请参考原理篇 2.keepalived原理请参考原理篇 3.基于lvs-dr+keepalived故障切换架构图如下: 二.部署 1.环境 2.准备RS的web ...

  6. IO流简要总结

    IO流小总结 IO流的本质就是用于数据的传输,根据流的方向的不同,有输入流.输出流.根据数据类型的不同,又有字节流.字符流. 字节流 字节输入流   InputStream 字节输出流   Outpu ...

  7. 设计模式系列6:适配器模式(Adapter Pattern)

    定义 将一个类的接口转换成客户希望的另一个接口,适配器模式使得原本由于接口不兼容而不能一起工作的那些类可以一起工作.    --<设计模式>GoF UML类图 使用场景 在遗留代码复用,类 ...

  8. 你应该学会的Python多版本管理工具Pyenv

    目录 Pyenv 简介 安装pyenv 通过pyenv安装python各种发行版 pyenv命令 多版本Python的管理 Pyenv常见问题Wiki Pyenv 简介 首先,该工具是在类linux环 ...

  9. Spring MVC(四)文件上传

    文件上传步骤 1.写一个文件上传的页面 2.写一个文件上传的控制器 注意: 1.method="post" 2.enctype="multipart/form-data& ...

  10. vue element-ui 分页组件封装

    <template> <el-pagination @size-change="handleSizeChange" @current-change="h ...