传送门

没啥好说的。就是一个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. Chrome - JavaScript调试技巧总结(浏览器调试JS)

    Chrome 是 Google 出品的一款非常优秀的浏览器,其内置了开发者工具(Windows 系统中按下 F12 即可开启),可以让我们方便地对 JavaScript 代码进行调试. 为方便大家学习 ...

  2. SpringBoot系列——Redis

    前言 Redis是一个缓存.消息代理和功能丰富的键值存储.StringBoot提供了基本的自动配置.本文记录一下springboot与redis的简单整合实例 官方文档:https://docs.sp ...

  3. Microsoft.Office.Interop.Excel 报错

    Microsoft.Office.Interop.Excel 报错 引用dll 在以下目录 C:\Windows\assembly\GAC_MSIL\Microsoft.Office.Interop. ...

  4. ASP.net<a>标签跨页面传参数

    //在goodsDetail.aspx页面接收 <script> //加载事件 $(function () { //第一种方式 var id=GetQueryString("id ...

  5. mysql-16进制、十进制互转

    先截取左边4位,再转换: conv(left(t1.DEVICEID, 4), 16, 10)      //转十进制 conv(left(t1.DEVICEID, 4), 10, 16)      ...

  6. JVM虚拟机基本概念

    一.JVM运行时数据区域1.1.程序计数器 一块较小的内存空间,当前线程所执行的字节码指示器.每个线程有一个独立的程序计数器1.2.Java虚拟机栈 线程私有,生命周期与线程相同 每个方法在执行时会创 ...

  7. 第三章:shiro授权认证

    授权:也叫访问控制,即在应用中控制谁能访问哪些资源(如访问页面/编辑数据/页面操作等). 主体:即访问应用的用户,在Shiro中使用Subject代表该用户.用户只有授权后才允许访问相应的资源. 资源 ...

  8. python迭代器与生成器及yield

    一.迭代器(itertor) 1.可迭代: 在Python中如果一个对象有__iter__()方法或__getitem__()方法,则称这个对象是可迭代的(iterable). 其中__iter__( ...

  9. Nginx Windows详细安装部署教程

    一.Nginx简介 Nginx (engine x) 是一个高性能的HTTP和反向代理服务器,也是一个IMAP/POP3/SMTP服务器.Nginx是由伊戈尔·赛索耶夫为俄罗斯访问量第二的Ramble ...

  10. Dynamics 365-为什么查到的Record的Id是Guid初始值

    通过代码查询CRM数据,这个是开发经常会碰到的情况,获取返回的EntityCollection之后,我们会拿Entity.Id做进一步操作.笔者最近碰到的情况,是Entity.Id是个初始值.先上一段 ...