题目:
A,B轮流走(A先)
A走前方次近的点,B走前方最近的点
距离为:
∣
a
i
−
a
j
∣
|a_i-a_j|
∣ai−aj∣
1.从哪个点出发,总距离<x,A与B的行走距离比值最小
2.从s出发,总距离<x,A,B分别的行走距离
题解:
暴力一般直接找每个起点对应A,B会到达的点
预处理:排序后,链表,找其前面后面两个范围内的点。(本题重点)
可以发现不论前面怎么走只要以此为起点每次的终点都是不会改变的,于是我们可以用倍增简化每次单跳的操作
倍增不仅要维护跳的点,还要维护A,B分别走了多少
恶心调了几天,终于调出来了。。。
对拍,调错,改动。。。
写的可能很丑
b
z
[
i
]
[
j
]
表
示
以
i
为
起
点
跳
2
j
次
所
到
达
的
点
bz[i][j]表示以i为起点跳2^j次所到达的点
bz[i][j]表示以i为起点跳2j次所到达的点
g
[
i
]
[
j
]
[
s
]
[
t
]
表
示
以
i
为
起
点
s
先
跳
,
跳
2
j
次
中
t
走
的
距
离
g[i][j][s][t]表示以i为起点s先跳,跳2^j次中t走的距离
g[i][j][s][t]表示以i为起点s先跳,跳2j次中t走的距离
似乎很绕,但总算绕出来了
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=1e6+10,INF=1e18;
int n;
int a[N];
int bz[N][20][2],g[N][20][2][2];
struct qu{int id,num;bool operator<(const qu x)const{return num<x.num;}}b[N];
int we[N];
int lst[N],nex[N],t[N];
void putin(int x,int c){lst[x]=x-1;nex[x-1]=x;t[x]=c;}
void del(int x){lst[nex[x]]=lst[x];nex[lst[x]]=nex[x];nex[x]=0;}
void init()
{
for(int i=1;i<=n;i++)
b[i].id=i,b[i].num=a[i];
sort(b+1,b+n+1);
for(int i=1;i<=n;i++)
we[b[i].id]=i,putin(i,b[i].id);
int fw[5];
for(int i=1;i<n;i++)
{
int k=we[i];
fw[1]=lst[k];fw[2]=lst[lst[k]];fw[3]=nex[k];fw[4]=nex[nex[k]];
g[i][0][1][1]=g[i][0][0][0]=INF;
for(int j=1;j<=4;j++)
{
if(!fw[j])continue;
int now=t[fw[j]];
int dis=abs(a[i]-a[now]);
if(g[i][0][0][0]>dis||(g[i][0][0][0]==dis&&a[bz[i][0][0]]>a[now]))
{
bz[i][0][1]=bz[i][0][0];
g[i][0][1][1]=g[i][0][0][0];
bz[i][0][0]=now;
g[i][0][0][0]=dis;
}
else if(g[i][0][1][1]>dis||(g[i][0][1][1]==dis&&a[bz[i][0][1]]>a[now]))
{
bz[i][0][1]=now;
g[i][0][1][1]=dis;
}
}
del(k);
}
}
void get_bz()
{
bz[n-1][0][1]=0;//可能是写法问题,不写这句就会出错
for(int i=1;i<=n;i++)
{
int k0=bz[i][0][0],k1=bz[i][0][1];
bz[i][1][0]=bz[k0][0][1];
g[i][1][0][0]=g[i][0][0][0]+g[k0][0][1][0];
g[i][1][0][1]=g[i][0][0][1]+g[k0][0][1][1];
bz[i][1][1]=bz[k1][0][0];
g[i][1][1][0]=g[i][0][1][0]+g[k1][0][0][0];
g[i][1][1][1]=g[i][0][1][1]+g[k1][0][0][1];
}//A跳完2^0次B跳
for(int j=2;j<=18;j++)
for(int i=1;i<=n;i++)
{
int k0=bz[i][j-1][0],k1=bz[i][j-1][1];
bz[i][j][0]=bz[k0][j-1][0];
g[i][j][0][0]=g[i][j-1][0][0]+g[k0][j-1][0][0];
g[i][j][0][1]=g[i][j-1][0][1]+g[k0][j-1][0][1];
bz[i][j][1]=bz[k1][j-1][1];
g[i][j][1][0]=g[i][j-1][1][0]+g[k1][j-1][1][0];
g[i][j][1][1]=g[i][j-1][1][1]+g[k1][j-1][1][1];
}//A跳完2^i(i>=1)次还是A跳
}
int dis[2];
void f(int x,int up)
{
int tim=1;dis[0]=0;dis[1]=0;
for(int i=18;i>=0;i--)
{
//0:B 1:A
if(!bz[x][i][tim])continue;
int tmp=g[x][i][tim][0]+g[x][i][tim][1];
if(tmp+dis[0]+dis[1]<=up)
{
dis[0]+=g[x][i][tim][0];
dis[1]+=g[x][i][tim][1];
x=bz[x][i][tim];
}
}
return ;
}
signed main()
{
scanf("%lld",&n);
for(int i=1;i<=n;i++)
scanf("%lld",&a[i]);
init();
get_bz();
int x,s;
scanf("%lld",&x);
double cas=1e9;int bj=1;
for(int i=1;i<=n;i++)
{
f(i,x);
//0:B 1:A
double tmp;
if(!dis[0]&&!dis[1])continue;
if(!dis[0])tmp=1e9;
else tmp=dis[1]*1.0/dis[0];
if(tmp<cas)
{
cas=tmp;
bj=i;
}
}printf("%lld\n",bj);
int q;
scanf("%lld",&q);
for(int k=1;k<=q;k++)
{
scanf("%lld%lld",&s,&x);
f(s,x);
printf("%lld %lld\n",dis[1],dis[0]);
}
}