AcWing 392. 会合
一个思路不难,但是实现起来有点毒瘤的题。
显然题目给出的是基环树(内向树)森林。
把每一个基环抠出来。
大力分类讨论:
- 若 \(a, b\) 不在一个联通量里,显然是 \(-1, -1\)
- 若 \(a, b\) 在同一颗子树内,他们聚合的点显然是最近公共祖先,因为如果再往上走,2的条件就不满足。
- 若 \(a, b\) 在同一联通量(同一颗基环树),两颗不同的子树内。显然他们必须走到树根,然后这时有两个选择:从 \(root[a]\) 走到 \(root[b]\),或反之。我们求出两种走的步数,按照题意进行比较即可。
第一次遇到内向树,找基环的时候不知道该如何搞。(偷瞄了一眼别人的代码)发现他是自底向上进行递归,跟往常我们写的树的自顶向下相反,学习了一下。
相比来说自底向上貌似对内向树代码简化很多(只需一次dfs),原因在于:
- 若自顶向下遍历,我们找到一个环的时候,可能他的子树中的某些点已经遍历过了,也就是说 \(dep\)、\(root\) 等数组都算的不对,可能需要二次 \(dfs\)。
- 若自底向上遍历,只有当找到环之后,一个点才会确保更新。
#include <cstdio>
#include <iostream>
#include <vector>
using namespace std;
const int N = 500005, L = 19;
int n, Q, fa[N][L], f[N], root[N], dep[N], sum[N], ult[N];
bool vis[N], ins[N];
int find(int x) { return x == f[x] ? x : f[x] = find(f[x]); }
void dfs(int u) {
vis[u] = ins[u] = true;
int v = fa[u][0];
if (ins[v]) {
// 此时从 v -> fa[v][0], ->..., -> u -> v... 构成一个环
int cnt = 0, y = v;
while (1) {
root[y] = y, dep[y] = 0, ult[y] = u;
sum[y] = ++cnt, ins[y] = false;
if (y == u) break;
y = fa[y][0];
}
return;
}
if (!vis[v]) dfs(v);
if (!root[u]) root[u] = root[v], dep[u] = dep[v] + 1, ins[u] = false;
for (int i = 1; i < L && fa[u][i - 1]; i++) fa[u][i] = fa[fa[u][i - 1]][i - 1];
}
int lca(int x, int y) {
if (dep[x] < dep[y]) swap(x, y);
for (int i = L - 1; ~i; i--)
if (dep[x] - (1 << i) >= dep[y]) x = fa[x][i];
if (x == y) return x;
for (int i = L - 1; ~i; i--)
if (fa[x][i] != fa[y][i]) x = fa[x][i], y = fa[y][i];
return fa[x][0];
}
int main() {
scanf("%d%d", &n, &Q);
for (int i = 1; i <= n; i++) f[i] = i;
for (int i = 1; i <= n; i++) scanf("%d", &fa[i][0]), f[find(i)] = find(fa[i][0]);
for (int i = 1; i <= n; i++) if (!vis[i]) dfs(i);
while(Q--) {
int a, b; scanf("%d%d", &a, &b);
if (find(a) != find(b)) puts("-1 -1");
else if(root[a] == root[b]) {
int p = lca(a, b);
printf("%d %d\n", dep[a] - dep[p], dep[b] - dep[p]);
} else {
int x = dep[a], y = dep[b], cx, cy;
if (sum[root[a]] < sum[root[b]]) cx = sum[root[b]] - sum[root[a]], cy = sum[ult[root[a]]] - cx;
else cy = sum[root[a]] - sum[root[b]], cx = sum[ult[root[a]]] - cy;
if (max(x + cx, y) < max(x, y + cy) || (max(x + cx, y) == max(x, y + cy) && (min(x + cx, y) < min(x, y + cy) || (min(x + cx, y) == min(x, y + cy) && x + cx >= y))))
printf("%d %d\n", x + cx, y);
else printf("%d %d\n", x, y + cy);
}
}
return 0;
}
AcWing 392. 会合的更多相关文章
- 392. Is Subsequence
392. Is Subsequence 水题,先是判断长度,长度t比s小,返回false,然后从左到右扫描t,然后同时扫描s,如果相同,s的index就往后拉一个,如果s的index等于s长度,返回t ...
- 腾讯机试题 AcWing 603 打怪兽
题目链接:https://www.acwing.com/problem/content/605/ 题目大意: 略 分析: 用dp[i][j]表示用j元钱能在前i只怪兽上所能贿赂到的最大武力值. 有一种 ...
- AcWing 143. 最大异或对
https://www.acwing.com/problem/content/145 #include <iostream> #include <algorithm> usin ...
- AcWing 153. 双栈排序
https://www.acwing.com/problem/content/155/ #include <cstring> #include <iostream> #incl ...
- acwing 3 完全背包
习题地址 https://www.acwing.com/problem/content/description/3/ 题目描述有 N 种物品和一个容量是 V 的背包,每种物品都有无限件可用. 第 i ...
- AcWing 164. 可达性统计
给定一张N个点M条边的有向无环图,分别统计从每个点出发能够到达的点的数量. 输入格式 第一行两个整数N,M,接下来M行每行两个整数x,y,表示从x到y的一条有向边. 输出格式 输出共N行,表示每个点能 ...
- AcWing 291.蒙德里安的梦想
题目:蒙德里安的梦想 链接:(蒙德里安的梦想)[https://www.acwing.com/problem/content/293/] 题意:求把N * M的棋盘分割成若干个1 * 2的长方形,有多 ...
- acwing 861. 二分图的最大匹配 模板
地址 https://www.acwing.com/problem/content/description/863/ 给定一个二分图,其中左半部包含n1n1个点(编号1~n1n1),右半部包含n2n ...
- acwing 851. spfa求最短路 模板
地址 https://www.acwing.com/problem/content/description/853/ 给定一个n个点m条边的有向图,图中可能存在重边和自环, 边权可能为负数. 请你求出 ...
随机推荐
- centos 新装的常见问题
1.没有1080分辨率 vi /etc/X11/xorg.conf Section "Monitor" Identifier "Monitor0" Vendor ...
- Python_爬虫伪装_ scrapy中fake_userAgent的使用
scrapy 伪装代理和fake_userAgent的使用 伪装浏览器代理 在爬取网页是有些服务器对请求过滤的不是很高可以不用ip来伪装请求直接将自己的浏览器信息给伪装也是可以的. 第一种方法: 1. ...
- MongoDB笔记2018.2.6
MongoDB笔记2018.2.6 1.先简单接触下linux,大部分教程是在linux环境下的操作,要不然看不懂教程 2.找教程或视频 教程推荐菜鸟教程 学习MongDB前需要懂一定的Mysql语法 ...
- android下vulkan与opengles纹理互通
先放demo源码地址:https://github.com/xxxzhou/aoce 06_mediaplayer 效果图: 主要几个点: 用ffmpeg打开rtmp流. 使用vulkan Compu ...
- 环境安装和pycharm中一些基本设置
一.Pycharm的使用和Python环境 1.python和pycharm的安装 python推荐版本3.7/3.8 pycharm选择社区版本 查看python版本在cmd中输入"pyt ...
- 面试官:小伙子,你给我说一下你对MySQL索引的理解吧
一.索引是什么? 索引是帮助MySQL高效获取数据的数据结构. 二.索引能干什么? 索引非常关键,尤其是当表中的数据量越来越大时,索引对于性能的影响愈发重要.索引能够轻易将查询性能提高好几个数量级,总 ...
- python中a+=b 和a=a+b的结果一样吗
这里涉及到可变类型和不可变类型. 可变类型:列表,字典,集合 不可变:数字,字符串,元祖 先看一下不可变类型的运算: +=运算 >>> a, b = 1, 2 >>> ...
- CA证书与https讲解
最近面试问到这个问题,之前了解过但答的不是很好,再补充补充一下https方面的知识. 备注:以下非原创文章. CA证书与https讲解 1.什么是CA证书. ◇ 普通的介绍信 想必大伙儿都听说过介绍信 ...
- Camtasia中对录制视频进行编辑——旁白
相信很多人都遇见过想要录制视频,但是不知道在电脑上用哪一款软件比较好,害怕自己录的视频导出来之后会有水印,或者在录制的过程中遇到麻烦,更或者下载一款带有病毒的软件.那么今天我便给大家推荐一款专业录制屏 ...
- 利用MathType在Word里输入几何符号的技巧
通过学习几何学的知识,我们发现其中包含的几何符号有很多,比如有表示图形的符号,如三角形,平行四边形,圆,角,圆弧等:还有表示位置关系的符号,如平行,垂直等:还有表示矢量等其他符号,那这些符号怎么打出来 ...