CF1550F Jumping Around
Posted Jozky86
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了CF1550F Jumping Around相关的知识,希望对你有一定的参考价值。
题意:
数轴上顺次有 n 个点
a
1
<
a
2
<
⋯
<
a
n
。
a_1 < a_2 < \\cdots < a_n。
a1<a2<⋯<an。
有一只小青蛙,初始时在
a
s
a_s
as处。小青蛙有两个参数:步长 d 和灵活程度 k。其中,步长 d 是确定的,而灵活程度 k 是可以调整的
小青蛙可以从某个点跳到另一个点。但这是有要求的:小青蛙能从 a i a_i ai跳到 a j a_j aj,当且仅当 d − k ≤ ∣ a i − a j ∣ ≤ d + k d-k\\leq |a_i-a_j|\\leq d+k d−k≤∣ai−aj∣≤d+k
给定 a 1 , . . . , a n a_1,...,a_n a1,...,an和 d。你需要回答 q 次询问,每次询问给定一个一个下标 i和灵活程度 k ,你需要回答:此时的小青蛙能否跳到 a i ? a_i? ai?
保 证 1 ≤ n , q ≤ 2 × 1 0 5 , 1 ≤ s , i ≤ n , 1 ≤ a i , d , k ≤ 1 0 6 , a 1 < a 2 < ⋯ < a n 。 保证 1\\leq n,q\\leq 2\\times 10^5,1\\leq s,i\\leq n,1\\leq a_i,d,k\\leq 10^6,a_1 < a_2 < \\cdots < a_n 。 保证1≤n,q≤2×105,1≤s,i≤n,1≤ai,d,k≤106,a1<a2<⋯<an。
题解:
我一开始想,满足这个式子
d
−
k
≤
∣
a
i
−
a
j
∣
≤
d
+
k
d-k\\leq |a_i-a_j|\\leq d+k
d−k≤∣ai−aj∣≤d+k就可以跳,那我直接查询区间[l,r]的相邻差值最大值和最小值,然后看是否符合式子。但是第二个样例就不对,随后我突然明白,u不能直接到达v,但是u可以先到达其他点x,再到达v。
我们现在换个思路想,当参数为k时,如果我们可以走到一个节点x,参数大于k时我们也可以走到该节点。那么我们就开始考虑对于每个节点,求出可以走到它的最小的k。
对于这个式子:
d
−
k
≤
∣
a
i
−
a
j
∣
≤
d
+
k
d-k\\leq |a_i-a_j|\\leq d+k
d−k≤∣ai−aj∣≤d+k
−
k
≤
∣
a
i
−
a
j
∣
−
d
≤
k
-k\\leq |a_i-a_j|-d\\leq k
−k≤∣ai−aj∣−d≤k
∣
∣
a
i
−
a
j
∣
−
d
∣
≤
k
| |a_i-a_j|-d|\\leq k
∣∣ai−aj∣−d∣≤k
也就是满足这个式子,点i就可以到达点j,我们可以将
∣
∣
a
i
−
a
j
∣
−
d
∣
| |a_i-a_j|-d|
∣∣ai−aj∣−d∣当作边权,如果点u可以到达点v,那么其路径上的最大值<=k,为了让u能到达v,我们希望路径上最大值最小,那不就是跑最小生成树
本题中边的数量是
O
(
n
2
)
O(n^2)
O(n2),prim和kruskal都会超时,因此要用另一个最小生成树的算法boruvka算法。
这个算法不详细介绍了,详情见boruvka算法
算法的关键(也是复杂度与边权有关的地方)就是找最小边权的边,本题中边权是有性质的
现在我们要想
∣
∣
a
i
−
a
j
∣
−
d
∣
≤
k
| |a_i-a_j|-d|\\leq k
∣∣ai−aj∣−d∣≤k值最小,设
a
i
a_i
ai在连通块内,
a
j
a_j
aj在连通块外,那对于每个
a
i
a_i
ai,我们找
a
j
a_j
aj最接近
a
i
+
d
a_i+d
ai+d或者
a
i
−
d
a_i-d
ai−d的点,然后取最小即可
具体操作为:
我们可以维护一个set,先存所有的a,然后对于一个连通块,枚举连通块内所有的点,把他们从set中删除,此时set中所有点都在这个连通块外。然后再枚举连通块内的所有点i,用set二分查找距离
a
i
+
d
a_i+d
ai+d或者
a
i
−
d
a_i-d
ai−d的点。直接在set上二分四次就找到了。最后再把所有点加回来。
二分找最小边权的复杂度是O(nlog n)
总复杂度是
O
(
n
l
o
g
2
n
)
O(nlog^2n)
O(nlog2n)
因为我们直到起点,把起点当作跟跑一边dfs,求出到其他点的路径上的最大值,如果询问中k大于这个最大值,就是Yes,否则就是No
代码:
#include <bits/stdc++.h>
#include <unordered_map>
#define debug(a, b) printf("%s = %d\\n", a, b);
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int, int> PII;
clock_t startTime, endTime;
//Fe~Jozky
const ll INF_ll= 1e18;
const int INF_int= 0x3f3f3f3f;
void read(){};
template <typename _Tp, typename... _Tps> void read(_Tp& x, _Tps&... Ar)
{
x= 0;
char c= getchar();
bool flag= 0;
while (c < '0' || c > '9')
flag|= (c == '-'), c= getchar();
while (c >= '0' && c <= '9')
x= (x << 3) + (x << 1) + (c ^ 48), c= getchar();
if (flag)
x= -x;
read(Ar...);
}
template <typename T> inline void write(T x)
{
if (x < 0) {
x= ~(x - 1);
putchar('-');
}
if (x > 9)
write(x / 10);
putchar(x % 10 + '0');
}
void rd_test()
{
#ifdef ONLINE_JUDGE
#else
startTime = clock ();
freopen("data.in", "r", stdin);
#endif
}
void Time_test()
{
#ifdef ONLINE_JUDGE
#else
endTime= clock();
printf("\\nRun Time:%lfs\\n", (double)(endTime - startTime) /以上是关于CF1550F Jumping Around的主要内容,如果未能解决你的问题,请参考以下文章
CF198B Jumping on Walls (DFS+剪枝)
CF1523H Hopping Around the Array
[CF1523H]Hopping Around the Array