P7518 & 省选联考2021 宝石
这是一篇极其简单连像我这样省三参加不了省选的蒟蒻都能看懂的题解
前置知识: 倍增LCA 二分 栈 题意
PS:这是一篇完全面向初学者的题解,会非常细,大佬请无视
没有思路的时候, 我们往往可以从简单的情况下手, 比如一条链
我们记
不妨先假设我们有一条链, 每个节点指向下一个要搜集的宝石(向上), 也就
这个时候
很简单, 链的情况我们已经解决了
然而这个算法的复杂度是
最后,
for(int i=20;i>=0;i--)
if(deep[f[x][i]]>=deep[y])
x=f[x][i];
从大到小枚举, 如果深度没有超过另一个节点就往上跳
自然而然的想到,这道题也可以用倍增来跳, 预处理一个
for(int i=25; i>=0; i--){
int next = f1[now][i];
if(t!=0 && deep[next]>=deep[T]) now=next, i=25;
}
好!链的情况解决链, 一般情况就很简单了。
(是不是讲的有点太细了
不难发现,
对于
对于
我们让
不妨从一个
那么答案是不是可以搜集到y个呢?显然不是, 万一某个
这时候仔细思考,答案有单调性,可以二分,(因为假如能从
所以最终的思路: 二分可以搜集到第几个颜色, 如果可以从该节点跳到x+1(倍增), 则满足
复杂度
简单实现
实现很简单
1. 首先预处理三个倍增, 第一个普通倍增求LCA, 另外两个是S, T链上的倍增。
既然要倍增, 我们首先要知道每个节点的父节点,然后dp。对于这道题, 我们要知道对于某个点Px, 祖先中离他最近的Px+1, Px-1才行。怎么做呢?
很简单:对树进行
for(int i=1; i<=n; i++){
for(int j=1; j<=28; j++){
f[i][j] = f[f[i][j-1]][j-1];
f1[i][j] = f1[f1[i][j-1]][j-1];
f2[i][j] = f2[f2[i][j-1]][j-1];
}
}
2.从S点找到最近的
3.在
至于代码, 实现已经讲了就不放吧,没多长
其实是我tcl不想整理