[CF1550F]Jumping Around

Posted Tan_tan_tann

tags:

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

Jumping Around

题解

很明显,当参数为 k k k时,如果我们可以走到一个节点 x x x,参数大于 k k k时我们也可以走到该节点。
我们可以考虑对于每个节点,求出可以走到它的最小的 k k k
这使得我们很快联想到了最小生成树,我们将边 ( u , v ) (u,v) (u,v)的权值看成能使 u u u一步走到 v v v的最小参数。显然从 u u u走到 v v v所需要的最小参数就是最小生成树上 u u u v v v的路径上的最短边。

考虑如何求出这个最小生成树,显然无论时 K r u s k a l Kruskal Kruskal还是 P r i m Prim Prim都是会 T T T飞的,考虑 B o r u v k a Boruvka Boruvka
考虑如何快速求出与一个点间所需参数最小 k k k,显然我们可以使用二分来解决。
对于每个节点,对应任意的参数 k k k,它所能到达的节点肯定是两段或一段连续的区间,我们先二分找到这个最小的 k k k,使得他能到达的区间中有一个与它所属集合不同的点。
对于一个区间中的点所属的集合,我们可以采用 s t st st来进行维护,我们只用记录下该区间的点都属于同一个集合时该集合的编号,当它属于两个或两个以上的集合时,就一定存在一个与它集合不同的点了。
而这个点又一定在其中一个区间的边界上,我们只需要找到这是哪一个边界,就可以知道时那个点了。

然后对于一个集合,找到所有属于这个集合的点与别的区间相连的参数最小的集合的对应点,以参数为权值与之连边即可。
由于我们的集合每次都将减小至少 1 2 \\frac{1}{2} 21,每次减少完了后我们都要处理一遍 s t st st表,加上二分,该过程的时间复杂度是 O ( n l o g 2   n ) O\\left(nlog^2\\,n\\right) O(nlog2n)的,虽然已经可以过了,但明显还有更优秀的做法。

对于一个点 i i i,我们可以将其要找的匹配点 j j j分成四类, a j ∈ ( − ∞ , a i − d ] , ( a i − d , a i ) , ( a i , a i + d ) , [ a i + d , ∞ ) a_{j}\\in (-\\infty,a_{i}-d],(a_{i}-d,a_{i}),(a_{i},a_{i}+d),[a_{i}+d,\\infty) aj(,aid],(aid,ai),(ai,ai+d),[ai+d,)
对于每一类,我们都可以利用单调性求出与之对应的使得参数最小的点。
譬如第一类,我们可以从点 1 1 1到点 n n n进行匹配,转移时, a i − d a_{i}-d aid的值明显实在增大的,所以我们也会有点源源不断地变得可以匹配。
为了在这些点中找到可以匹配的最小集合,我们需要记录下当前所需参数最小的两个集合。
加入的新点参数必定小于旧点,直接更新即可。对于要匹配的点,找到这两个点中与它所属集合不同的参数最小的点匹配即可。
另外 3 3 3类同理,都可以这样利用指针维护。
这样我们就使得匹配的时间复杂度降到了 O ( n ) O\\left(n\\right) O(n),建生成树的总时间复杂度就变成了 O ( n l o g   n ) O\\left(nlog\\,n\\right) O(nlogn)

建出生成树后,我们就以点 s s s为根,计算出 s s s到每个节点所经过的路径中权值最大的边,询问时看与 k k k的大小关系即可。
时间复杂度 O ( n l o g   n ) O\\left(nlog\\,n\\right) O(nlogn),虽然常数可能会有点大

源码

#include<bits/stdc++.h>
using namespace std;
#define MAXN 200005
#define lowbit(x) (x&-x)
#define reg register
#define pb push_back
#define mkpr make_pair
#define fir first
#define sec second
#define lson (rt<<1)
#define rson (rt<<1|1)
typedef long long LL;
typedef unsigned long long uLL;
const int INF=0x3f3f3f3f;
const int mo=1e9+7;
const int inv2=5e8+4;
const int jzm=2333;
const int orG=3,invG=332748118;
const int lim=300000;
const double Pi=acos(-1.0);
typedef pair<int,int> pii;
const double PI=acos(-1.0);
template<typename _T>
_T Fabs(_T x){return x<0?-x:x;}
template<typename _T>
void read(_T &x){
	_T f=1;x=0;char s=getchar();
	while(s>'9'||s<'0'){if(s=='-')f=-1;s=getchar();}
	while('0'<=s&&s<='9'){x=(x<<3)+(x<<1)+(s^48);s=getchar();}
	x*=f;
}
template<typename _T>
void print(_T x){if(x<0){x=(~x)+1;putchar('-');}if(x>9)print(x/10);putchar(x%10+'0');}
int gcd(int a,int b){return !b?a:gcd(b,a%b);}
int add(int x,int y){return x+y<mo?x+y:x+y-mo;}
int qkpow(int a,int s){int t=1;while(s){if(s&1)t=1ll*a*t%mo;a=1ll*a*a%mo;s>>=1;}return t;}
int n,q,s,d,a[MAXN],fa[MAXN],head[MAXN],tot,cnt,mind[MAXN];pii p[MAXN];
int id,f1,f2,dis1,dis2,pa[MAXN],maxw[MAXN];
struct edge{int to,nxt,paid;}e[MAXN<<1];
void addEdge(int u,int v,int w){e[++tot]=(edge){v,head[u],w};head[u]=tot;}
void makeSet(int x){for(int i=1;i<=x;i++)fa[i]=i;}
int findSet(int x){return fa[x]==x?x:fa[x]=findSet(fa[x]);}
void unionSet(int a,int b){int u=findSet(a),v=findSet(b);if(u==v)return ;fa[u]=v;}
void insert(int x,int w){
	if(findSet(x)==findSet(f1))f1=x,dis1=w;
	else f2=f1,dis2=dis1,f1=x,dis1=w;
}
void dosaka(int u,int fa){
	for(int i=head[u];i;i=e[i].nxt){
		int v=e[i].to,w=e[i].paid;if(v==fa)continue;
		maxw[v]=max(maxw[u],w);dosaka(v,u);
	}
}
signed main(){
	read(n);read(q);read(s);read(d);
	for(int i=1;i<=n;i++)read(a[i]);makeSet(n);
	while(cnt<n-1){
		for(int i=1;i<=n;i++)mind[i]=INF,pa[i]=fa[i];
		id=0,f1=0,f2=0,dis1=INF,dis2=INF;
		for(int i=1;i<=n;i++){
			if(f1)dis1=a[i]-a[f1]-d;if(f2)dis2=a[i]-a[f2]-d;
			while(id<n&&a[i]-a[id+1]>=d)id++,insert(id,a[i]-a[id]-d);
			if(findSet(f1)!=findSet(i)){if(dis1<mind[i])mind[i]=dis1,p[i]=mkpr(i,f1);}
			else{if(dis2<mind[i])mind[i]=dis2,p[i]=mkpr(i,f2);}
		}
		id=n+1,f1=0,f2=0,dis1=INF,dis2=INF;
		for(int i=n;i>0;i--){
			if(f1)dis1=a[f1]-a[i]-d;if(f2)以上是关于[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!