CF1550F Jumping Around

Posted Jozky86

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了CF1550F Jumping Around相关的知识,希望对你有一定的参考价值。

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 dkaiajd+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 。 1n,q2×1051s,in1ai,d,k106a1<a2<<an

题解:

我一开始想,满足这个式子 d − k ≤ ∣ a i − a j ∣ ≤ d + k d-k\\leq |a_i-a_j|\\leq d+k dkaiajd+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 dkaiajd+k
− k ≤ ∣ a i − a j ∣ − d ≤ k -k\\leq |a_i-a_j|-d\\leq k kaiajdk
∣ ∣ a i − a j ∣ − d ∣ ≤ k | |a_i-a_j|-d|\\leq k aiajdk
也就是满足这个式子,点i就可以到达点j,我们可以将 ∣ ∣ a i − a j ∣ − d ∣ | |a_i-a_j|-d| aiajd当作边权,如果点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 aiajdk值最小,设 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 aid的点,然后取最小即可
具体操作为:
我们可以维护一个set,先存所有的a,然后对于一个连通块,枚举连通块内所有的点,把他们从set中删除,此时set中所有点都在这个连通块外。然后再枚举连通块内的所有点i,用set二分查找距离 a i + d a_i+d ai+d或者 a i − d a_i-d aid的点。直接在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+剪枝)

cf510 D. Fox And Jumping(dp)

CF1523H Hopping Around the Array

[CF1523H]Hopping Around the Array

[CF1038F]Wrap Around[AC自动机+dp]

Super Jumping! Jumping! Jumping!