把ab各走一次算一步
f[i][j]表示i点跳2^j步走到的点
da[i][j]表示i点跳2^j步a走的路程
db[i][j]表示i点跳2^j步b走的路程
- 倒着扫一遍求从i点a走出一次走到的点toi,记录da[i][0]。然后,我们把to[i]和i连边
2.倒着扫一遍求从i ,b走出一次走到的点t,再枚举所有i的出边,设边的另一端为p,则p走“一步”就是走到了t了,记录f[p][0]。同理,记录db。 - 倍增,注意可能最后a可以多走一步。
- 。。。
- 这道题主要是初始化难,其他随便搞搞调调都行了。
#include<bits/stdc++.h>
#define N 100010
#define inf 2147483647
#define ll long long
#define point(a) multiset<a>::iterator
#define mod (ll)(1e9+7)
#define mem(a,b) memset(a,b,sizeof (a))
#define open(x) freopen(x".in","r",stdin);freopen(x".out","w",stdout);
using namespace std;
struct rel
{ll v,fr;}e[N];
ll n,i,j,k,t,m,disa,disb,ans,tot;
ll H[N],to[N],tt[N],f[N][20],da[N][20],db[N][20],s,x,tail[N];
//to -a
struct node
{
ll id,h;
bool operator < (const node b) const
{
node a=*this;
return a.h== b.h ? H[a.id] < H[b.id] : a.h < b.h;
}
};
multiset<node> a;
long double rat,cmp;
void redouble()
{
for(j=1;j<20;j++)
for(i=1;i<=n;i++)
{
if(f[i][j-1] == n) continue;
f[i][j] = f[f[i][j-1]][j-1];
da[i][j] = da[i][j-1] + da[f[i][j-1]][j-1];
db[i][j] = db[i][j-1] + db[f[i][j-1]][j-1];
}
return ;
}
void add(ll u,ll v)
{
e[++tot].v=v;
e[tot].fr=tail[u];
tail[u]=tot;
}
void choose_go(char p , ll s,ll t,ll d)
{
if(p=='a')
{
da[s][0]=d;
to[s]=t;
add(t,s);
}else
{
for(ll p=tail[s];p;p=e[p].fr)
{
db[e[p].v][0]=d;
f[e[p].v][0]=t;
}
}
}
void init()
{
a.clear();
tot=0;
mem(to,0); mem(tail,0); mem(da,0); mem(db,0); mem(f,0);
for(i=n;i>0;i--)
{
a.insert((node){i,H[i]});
point(node) it = a.find((node){i,H[i]}),l=it,r=it;
point(node) rbegin = a.end(),begin = a.begin(),end=a.end(); --rbegin;
for(ll j=1;j<=2;j++)
{
if(l!=begin) -- l;
if(r!=rbegin) ++ r;
}
++r;
node x,y;
x=y=(node){inf,inf};
for(point(node) p =l;p!=r;++p)if(p!=it)
{
node now=(node){p->id , abs(p->h - H[i])};
if(now < x)
{
y=x;
x=now;
}else if(now < y) y=now;
}
//to , pre , da
if(y.id!=inf)choose_go('a',i,y.id,y.h);
}
a.clear();
for(i=n;i>0;i--)
{
a.insert((node){i,H[i]});
point(node) it = a.find((node){i,H[i]}),l=it,r=it;
--l,++r;
ll decx = it == a.begin() ? inf : H[i] - l->h;
ll decy = r == a.end() ? inf : r->h - H[i];
if(decx == inf && decy == inf)continue;
if(decx < decy || decx==decy ) choose_go('b',i,l->id,decx); else if(decx > decy) choose_go('b',i,r->id,decy);
//***
}
redouble();
return ;
}
void drive(ll s,ll x)
{
disa=disb=0;
ll p=s;
for(ll i=19;i>=0;i--) if(f[p][i]) if(disa + disb + da[p][i] + db[p][i]<=x)
{
disa += da[p][i];
disb += db[p][i];
p= f[p][i];
}
if(to[p]) if(disa + disb + da[p][0] <=x) disa += da[p][0];
return ;
}
int main()
{
scanf("%lld\n",&n);
for(i=1;i<=n;i++)scanf("%lld",&H[i]);
init();
scanf("%lld",&x);
cmp=inf;
for(i=1;i<=n;i++)
{
drive(i,x);
if(disb!=0) rat=(long double)disa / disb; else rat = inf-1;
if(rat < cmp)
{
cmp=rat;
ans=i;
}else
if(rat == cmp)
{
if(H[i] > H[ans]) ans=i;
}
}
printf("%lld\n",ans);
scanf("%lld",&m);
while(m--)
{
scanf("%lld%lld",&s,&x);
drive(s,x);
printf("%lld %lld\n",disa,disb);
}
return 0;
}