倍增优化DP
用链表 或者 平衡树 预处理(set)离每一个结点最近的点和第二近的点。
F(I,j,k)表示当前在j点走2^ i天到达的下一个点 k=0/1代表是A或者B先开车。DA(I,J,K)表示当前在j点走2^i天到达的下一个点A一共走的距离 k=0/1代表是A或者B先开车
DB(I,J,K)表示当前在j点走2^i天到达的下一个点B一共走的距离 k=0/1代表是A或者B先开车
就可以啦orz
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=100050;
const double inf=1e17;
struct node{
ll id,l,r;
ll h;
}p[N];
ll pos[N],f[20][100001][2];
ll da[20][100001][2],db[20][100001][2],dx,dy;
ll x0,n,m;
ll ga[N],gb[N];
bool comp(node a,node b){
return a.h<b.h;
}
ll read(){
ll sum=0,f=1;
char ch=getchar();
while(ch>'9'||ch<'0'){
if(ch=='-')f=-1;
ch=getchar();
}
while(ch<='9'&&ch>='0'){
sum=(sum<<3)+(sum<<1)+ch-'0';
ch=getchar();
}
return sum*f;
}
bool judge(ll l,ll m,ll r){
if(!l)return 0;
if(!r)return 1;
return p[m].h-p[l].h<=p[r].h-p[m].h;
}
ll dis(ll i,ll j){
return abs(p[pos[i]].h-p[pos[j]].h);
}
void work(ll s,ll x){
dx=0;dy=0;
int k=0;
for(int i=18;i>=0;i--)
if(f[i][s][k]&&dx+dy+da[i][s][k]+db[i][s][k]<=x){
dx+=da[i][s][k];
dy+=db[i][s][k];
if(i==0)k=1;
s=f[i][s][k];
}
}
int main(){
// freopen("drive.in","r",stdin);
// freopen("drive.out","w",stdout);
n=read();
for(int i=1;i<=n;i++)
{
p[i].h=read();
p[i].id=i;
}
sort(p+1,p+n+1,comp);
for(int i=1;i<=n;i++){
p[i].l=i-1;
p[i].r=i+1;
pos[p[i].id]=i;
}
p[1].l=0;p[n].r=0;
for(int i=1;i<=n;i++)
{
int j=pos[i],l=p[j].l,r=p[j].r;
if(judge(l,j,r)){
gb[i]=p[l].id;
if(judge(p[l].l,j,r))ga[i]=p[p[l].l].id;
else ga[i]=p[r].id;
}
else{
gb[i]=p[r].id;
if(judge(l,j,p[r].r))ga[i]=p[l].id;
else ga[i]=p[p[r].r].id;
}
if(l)p[l].r=r;
if(r)p[r].l=l;
}
for(int i=1;i<=n;i++)
{
if(ga[i]){f[0][i][0]=ga[i];da[0][i][0]=dis(i,ga[i]);}
if(gb[i]){f[0][i][1]=gb[i];db[0][i][1]=dis(i,gb[i]);}
da[0][i][1]=0;
db[0][i][0]=0;
}
int k;
for(int i=1;i<=18;i++)
for(int j=1;j<=n;j++)
for(int t=0;t<=1;t++)
{
if(i==1)k=t^1;
else k=t;
if(f[i-1][j][t])f[i][j][t]=f[i-1][f[i-1][j][t]][k];
if(f[i][j][t]){
da[i][j][t]=da[i-1][f[i-1][j][t]][k]+da[i-1][j][t];
db[i][j][t]=db[i-1][f[i-1][j][t]][k]+db[i-1][j][t];
}
}
x0=read();m=read();
double mini=inf;
int ans;
for(int i=1;i<=n;i++)
{
work(i,x0);
if(dy&&(1.0*dx/dy)<mini)
{
mini=1.0*dx/dy;
ans=i;
}
}
cout<<ans<<endl;
int x,s;
for(int i=1;i<=m;i++)
{
s=read();x=read();
work(s,x);
cout<<dx<<' '<<dy<<endl;
}
return 0;
}