开车旅行[巧妙的倍增][set]

传送门

对于找第一第二近,用set+lower_bound,预处理出nxt_A nxt_B 表示A,B下一步走到哪里

然后倍增 , st_A[i][j] 表示从i往后2^j步A走了多少 B同理

nxt[i][j] 表示往后走2^j步的位置

类似lca那样预处理就好了


//一直RE但对拍一小时后的伪AC代码
#include<bits/stdc++.h>
#define N 500005
#define inf 0x3fffffff
#define LL long long 
using namespace std;
LL n,x0,m;
LL a[N],h[N];
set<LL> S;
LL nxt_A[N] , nxt_B[N] , H_A[N] , H_B[N];
LL nxt[N][20] , st_A[N][20] , st_B[N][20];
LL read(){
	LL cnt=0,f=1;char ch=0;
	while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}
	while(isdigit(ch))cnt=cnt*10+(ch-'0'),ch=getchar();
	return cnt*f; 
}
void getab(LL x,LL pos,LL &ans1,LL &ans2){
	for(LL i=18;i>=0;i--){
		if(st_A[pos][i] + st_B[pos][i] <= x && nxt[pos][i]){
			ans1 += st_A[pos][i];
			ans2 += st_B[pos][i];
			x -= (st_A[pos][i] + st_B[pos][i]);
			pos = nxt[pos][i]; 
		}
	}
	if(nxt_A[pos] && st_A[pos][0] <= x) ans1 += st_A[pos][0];
}
int main(){
	n=read();
	for(LL i=1;i<=n;i++) a[i]=read(),h[a[i]]=i;
	S.insert(inf) , S.insert(-inf);
	S.insert(a[n]) , S.insert(a[n-1]);
	nxt_B[n-1] = n; 
	for(LL i=n-2;i>=1;i--){
		LL nxt = *S.lower_bound(a[i]);
		LL pre = *--S.lower_bound(a[i]);
		set<LL>::iterator it;
		it = S.lower_bound(nxt); if(*it!=inf) ++it;
		LL nxt_nxt = *it;
		it = S.lower_bound(pre); if(*it!=-inf) --it;
		LL pre_pre = *it;
		if(nxt_nxt-a[i] < a[i]-pre) nxt_A[i] = h[nxt_nxt] , nxt_B[i] = h[nxt];
		else if(a[i]-pre_pre <= nxt-a[i]) nxt_A[i] = h[pre_pre] , nxt_B[i] = h[pre]; 
		else if(nxt-a[i] < a[i]-pre) nxt_A[i] = h[pre] , nxt_B[i] = h[nxt];
		else nxt_A[i] = h[nxt] , nxt_B[i] = h[pre];
		S.insert(a[i]);
	}
	for(LL i=1;i<n;i++) nxt[i][0] = nxt_B[nxt_A[i]];
	for(LL i=1;i<=n;i++){
		if(nxt_A[i]) st_A[i][0] = H_A[i] = abs(a[nxt_A[i]] - a[i]);
		if(nxt_B[i]) H_B[i] = abs(a[nxt_B[i]] - a[i]);
		if(nxt[i][0]) st_B[i][0] = abs(a[nxt[i][0]] - a[nxt_A[i]]);
	}	
	for(LL i=1;i<=18;i++)
		for(LL j=1;j<=n;j++){
			nxt[j][i] = nxt[nxt[j][i-1]][i-1];
			st_A[j][i] = st_A[j][i-1] + st_A[nxt[j][i-1]][i-1];
			st_B[j][i] = st_B[j][i-1] + st_B[nxt[j][i-1]][i-1];
		}
	x0=read();
	LL u1=1,u2=0,H=0;
	LL ans=1;
	for(LL i=1;i<=n;i++){
		LL f1=0,f2=0;
		getab(x0,i,f1,f2);
		if(!f2) continue;
		if(f2*u1 > f1*u2 || (f2*u1 == f1*u2 && a[i]>H)) u1=f1 , u2=f2 , H=a[i] , ans=i;
	}
	printf("%lld\n",ans);
	m=read();
	while(m--){
		LL s=read(),x=read();
		LL f1=0,f2=0;
		getab(x,s,f1,f2);
		printf("%lld %lld\n",f1,f2);
	}return 0;
}

猜你喜欢

转载自blog.csdn.net/sslz_fsy/article/details/83477802