这篇博客有许多使用到 STL 的地方,由于本人实在是记不全,所以我也参考了北大的一些教材,就别说我黈力了 QwQ
今天讲的是数据结构啦(也是我这个蒟蒻最喜欢的
这些吧都是些挺水的东西,我就口胡口胡。(结果口胡着口胡着过万了??????)
值得一提的是 队列常用于 bfs,栈一般就是用于中序和后序遍历
堆是一种很有意思的数据结构
它允许元素的堆顶弹出,堆低插入,而 c++ 当中的 stl 提供了 priority_queue(优先队列)这个容器,允许你对于这个队列采用特定的方式优先排序
对于一个堆,我们一般只说大根堆和小根堆,c++ 默认是大根堆,想要实现小根堆,我们可以这样
priority_queue<int, vector<int>, greater<int> >;//注意此处 > 要用空格空开,有可能识别为右移
我们有一棵树,定义一棵树上的点到根结点的路径上所有的点都是它的祖先,LCA 指的就是两个数的最近公共祖先
步骤大体是这样
1. 如果 A 的深度小于 B 的深度,就把他们互换
2. 把 a 向上调到和 b 一样的高度,直到 ab 一样高(此时 ab 可以进行互换)
3. 把 a 和 b 一起上调,直到 ab 相同
这种算法复杂度是 O(deep) 的,但是当树是一条类似于链的结构,就废了,考虑为什么?
我们是一层一层跳的,自然会很慢,所以我们可以考虑倍增着来求 LCA
令
p [x] [i]
表示 x 向后 2^i 的祖先是谁,显然 p[x] [i] = p[ p [x] [i - 1] ] [i - 1]
用这张图举例,我们想要求出 4,5 的 LCA
求 LCA 的全部思路就是
1. 先 dfs 所有点,处理出每一个点的深度
2.然后把深度更深的那一个点(4)一个点地一个点地往上跳,直到到某个点(3)和另外那个点(5)的深度一样
然后两个点一起一个点地一个点地往上跳,直到到某个点(就是最近公共祖先)两个点“变”成了一个点
不过有没有发现一个点地一个点地跳很浪费时间?
如果一下子跳到目标点内存又可能不支持,相对来说倍增的性价比算是很高的
倍增的话就是一次跳2^i个点,不难发现深度差为x时,深度更深的那个点就需要跳x个点
所以代码就是这个样子
void LCA()
{
if (depth[a] < depth[b])
swap(a, b);
int c = depth[a] - depth[b];
for (int i = 0; i <= 14; i++)
{
if (c & (1 << i))
{
a = up[a][i];
}
}
}
这样子看起来很不错对吧,但是会出现一个问题,那就是挑到的公共祖先不一定是最近的
所以倍增找LCA的方法是这样的
在两个人平了之后,从最大可以跳的步数开始跳(一定是2^i),如果跳的到的位置一样,就不跳,如果不一样才跳,每次跳的路程是前一次的一半
这样做有一个缺点,就是它找到的点是最靠近LCA的点,也就是再跳一步就是LCA
f[i][0] = fa[i];
要注意到的是最好对于根节点的值附一下初值
原文:https://www.cnblogs.com/this-is-M/p/11222667.html