NOIP2012day1 開車旅行(倍增跳躍)
阿新 • • 發佈:2018-11-06
題意
https://www.luogu.org/problemnew/show/P1081
思路
首先
分的暴力跟著晦澀的題意強行打了一遍,然後對題意有了更深刻的理解,發現可以預處理小
和小
從某個點出發下一個走的點
,就不用每次
一遍找了,這樣就成了
分。
不管是第一近還是第二近的點,都是因為海拔相近,所以用連結串列或set維護一個海拔有序的序列,然後按一定順序刪除/加入,在
的位置查詢即可。
知道了走一步的位置,那麼走
步也能應聲而出了,預處理倍增陣列,然後倒置迴圈倍增跳躍即可。
程式碼
#include<bits/stdc++.h>
#define FOR(i,x,y) for(register int i=(x);i<=(y);++i)
#define DOR(i,x,y) for(register int i=(x);i>=(y);--i)
#define N 100003
typedef long long LL;
using namespace std;
int h[N],L[N],R[N],idx[N],nxt[N][2],dis[N][2],g[N][23];
LL f[N][23][2];
int n,m;
struct node
{
int x,val;
bool operator <(const node &_)const{return val<_.val;}
}a[N];
void init()
{
memset(dis,0x7f,sizeof(dis));
FOR(i,1,n)a[i]=(node){i,h[i]};
sort(a+1,a+1+n);
FOR(i,1,n)idx[a[i].x]=i;
FOR(i,1,n)L[i]=i-1,R[i]=i+1;
L[1]=R[n]=0;
FOR(i,1,n)
{
int k=idx[i];
if(L[k])
{
k=L[k];
nxt[i][0]=a[k].x,dis[i][0]=h[i]-a[k].val;
if(L[k])
{
k=L[k];
nxt[i][1]=a[k].x,dis[i][1]=h[i]-a[k].val;
}
}
k=idx[i];
if(R[k])
{
k=R[k];
if(a[k].val-h[i]<dis[i][0])
{
nxt[i][1]=nxt[i][0],dis[i][1]=dis[i][0];
nxt[i][0]=a[k].x,dis[i][0]=a[k].val-h[i];
}
else if(a[k].val-h[i]<dis[i][1])
nxt[i][1]=a[k].x,dis[i][1]=a[k].val-h[i];
if(R[k])
{
k=R[k];
if(a[k].val-h[i]<dis[i][1])
nxt[i][1]=a[k].x,dis[i][1]=a[k].val-h[i];
}
}
k=idx[i];
L[R[k]]=L[k],R[L[k]]=R[k];
}
FOR(i,1,n)
{
g[i][0]=nxt[nxt[i][1]][0];
f[i][0][1]=dis[i][1];
f[i][0][0]=dis[nxt[i][1]][0];
}
FOR(j,1,20)
FOR(i,1,n)
{
g[i][j]=g[g[i][j-1]][j-1];
f[i][j][0]=f[i][j-1][0]+f[g[i][j-1]][j-1][0];
f[i][j][1]=f[i][j-1][1]+f[g[i][j-1]][j-1][1];
}
}
void Travel(int s,int X,LL &A,LL &B)
{
A=B=0;
DOR(i,20,0)
if(g[s][i]&&A+B+f[s][i][1]+f[s][i][0]<=X)
{
A+=f[s][i][1];
B+=f[s][i][0];
s=g[s][i];
}
if(nxt[s][1]&&A+B+dis[s][1]<=X)
A+=dis[s][1];
}
bool Smaller(LL a,LL b,LL c,LL d)
{
if(b==0)return false;
else if(d==0)return true;
else return 1.0*a/b<1.0*c/d;
}
bool Equal(LL a,LL b,LL c,LL d)
{
if(b==0&&d==0)return 1;
else if(b*d==0)return 0;
else return fabs(1.0*a/b-1.0*c/d)<=1e-7;
}
int main()
{
scanf("%d",&n);
FOR(i,1,n)scanf("%d",&h[i]);
init();
int X0,ansH=-2e9,ansS;
LL ansA=2e9,ansB=0;
scanf("%d",&X0);
FOR(i,1,n)
{
LL resA,resB;
Travel(i,X0,resA,resB);
if(Smaller(resA,resB,ansA,ansB)||Equal(resA,resB,ansA,ansB)&&h[i]>ansH)
{
ansS=i;
ansH=h[i];
ansA=resA,ansB=resB;
}
}
printf("%d\n",ansS);
scanf("%d",&m);
while(m--)
{
int s,t;LL A,B;
scanf("%d%d",&s,&t);
Travel(s,t,A,B);
printf("%lld %lld\n",A,B);
}
return 0;
}