D3(没写完

说在博客前

这篇博客有许多使用到 STL 的地方,由于本人实在是记不全,所以我也参考了北大的一些教材,就别说我黈力了 QwQ

数据结构

今天讲的是数据结构啦(也是我这个蒟蒻最喜欢的

一些天天见面的好盆友

栈,队列

这些吧都是些挺水的东西,我就口胡口胡。(结果口胡着口胡着过万了??????)

值得一提的是 队列常用于 bfs,栈一般就是用于中序和后序遍历

堆是一种很有意思的数据结构
它允许元素的堆顶弹出,堆低插入,而 c++ 当中的 stl 提供了 priority_queue(优先队列)这个容器,允许你对于这个队列采用特定的方式优先排序

对于一个堆,我们一般只说大根堆和小根堆,c++ 默认是大根堆,想要实现小根堆,我们可以这样

priority_queue<int, vector<int>, greater<int> >;//注意此处 > 要用空格空开,有可能识别为右移

倍增求 LCA

我们有一棵树,定义一棵树上的点到根结点的路径上所有的点都是它的祖先,LCA 指的就是两个数的最近公共祖先

步骤大体是这样

1. 如果 A 的深度小于 B 的深度,就把他们互换

2. 把 a 向上调到和 b 一样的高度,直到 ab 一样高(此时 ab 可以进行互换)

3. 把 a 和 b 一起上调,直到 ab 相同

扫描二维码关注公众号,回复: 6831624 查看本文章

这种算法复杂度是 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的点,也就是再跳一步就是LCA

f[i][0] = fa[i];

要注意到的是最好对于根节点的值附一下初值

猜你喜欢

转载自www.cnblogs.com/this-is-M/p/11222667.html
D3