传送门
problem
数据范围:
1
≤
n
≤
1
0
5
1≤n≤10^5
1≤n≤105,
1
≤
m
≤
1
0
4
1≤m≤10^4
1≤m≤104。
solution
感觉这道题挺妙的。
首先要解决的一个问题是,怎么找到题目中定义的最近城市和次近城市?
一个思路就是从
n
∼
1
n\sim 1
n∼1 倒着扫,处理到
i
i
i 时,我们想知道
[
i
+
1
,
n
]
[i+1, n]
[i+1,n] 中,
h
i
h_i
hi 的前驱,后继,前驱的前驱,后继的后继,因为只最近和次近肯定在这
4
4
4 个点中,排序判一下具体是哪两个即可。
由于我们要支持插入,查询前驱后继这些操作,可以很方便地用 set 维护。
接下来就是询问了。两种询问实质上是一样的,因为第一个询问可以通过枚举每一个点转换成第二个询问。
暴力的做法就是直接模拟,先走一步 A,然后走 B,再走 A,
⋯
\cdots
⋯,直到不能走为止。
怎么优化这个暴力呢,不妨考虑倍增。记 A,B 各走一次为一轮,暴力跳看能走几轮,最后特判一下 A 是否可以再走一次即可。
时间复杂度
O
(
n
log
n
)
O(n\log n)
O(nlogn)。
PS:代码中倍增是以
1
1
1 为下标的,
0
0
0 记的是 A 跳一次的信息。
code
#include<bits/stdc++.h>
#define ll long long
using namespace std
;
namespace IO
{
const int Rlen
=1<<22|1;
char buf
[Rlen
],*p1
,*p2
;
inline char gc(){
return (p1
==p2
)&&(p2
=(p1
=buf
)+fread(buf
,1,Rlen
,stdin),p1
==p2
)?EOF:*p1
++;
}
template<typename T
>
inline T
Read(){
char c
=gc();T x
=0,f
=1;
while(!isdigit(c
)) f
^=(c
=='-'),c
=gc();
while( isdigit(c
)) x
=(x
+(x
<<2)<<1)+(c
^48),c
=gc();
return f
?x
:-x
;
}
inline int in() {return Read
<int>();}
}
using IO
::in
;
const int N
=1e5+5;
int n
,m
,pos
,X0
,h
[N
];
ll disA
[N
],disB
[N
],posA
[N
],posB
[N
],inf
=1e15;
ll p
[N
][21],A
[N
][21],B
[N
][21];
set
<ll
>S
;
unordered_map
<ll
,int>Map
;
struct node
{ll h
,dis
;}tmp
[5];
bool operator<(const node
&p
,const node
&q
) {return (p
.dis
==q
.dis
)?p
.h
<q
.h
:p
.dis
<q
.dis
;}
ll
Abs(ll x
) {return x
>0?x
:-x
;}
void prework(){
S
.insert(inf
),S
.insert(inf
-1),S
.insert(-inf
),S
.insert(-inf
+1);
for(int i
=n
;i
>=1;--i
){
S
.insert(h
[i
]);
tmp
[1].h
=*--S
.lower_bound(h
[i
]);
tmp
[2].h
=*--S
.lower_bound(tmp
[1].h
);
tmp
[3].h
=*S
.upper_bound(h
[i
]);
tmp
[4].h
=*S
.upper_bound(tmp
[3].h
);
for(int j
=1;j
<=4;++j
) tmp
[j
].dis
=Abs(tmp
[j
].h
-h
[i
]);
sort(tmp
+1,tmp
+5);
disA
[i
]=tmp
[2].dis
,posA
[i
]=Map
[tmp
[2].h
];
disB
[i
]=tmp
[1].dis
,posB
[i
]=Map
[tmp
[1].h
];
if(posA
[i
]) A
[i
][0]=disA
[i
],p
[i
][0]=posA
[i
];
if(posB
[posA
[i
]]) A
[i
][1]=disA
[i
],B
[i
][1]=disB
[posA
[i
]],p
[i
][1]=posB
[posA
[i
]];
for(int j
=2;j
<=20;++j
){
p
[i
][j
]=p
[p
[i
][j
-1]][j
-1];
A
[i
][j
]=A
[i
][j
-1]+A
[p
[i
][j
-1]][j
-1];
B
[i
][j
]=B
[i
][j
-1]+B
[p
[i
][j
-1]][j
-1];
}
}
}
void calc(int S
,int X
,ll
&ansA
,ll
&ansB
){
ansA
=ansB
=0;
for(int i
=20;i
>=1;--i
){
if(p
[S
][i
]&&ansA
+ansB
+A
[S
][i
]+B
[S
][i
]<=X
){
ansA
+=A
[S
][i
];
ansB
+=B
[S
][i
];
S
=p
[S
][i
];
}
}
if(p
[S
][0]&&ansA
+ansB
+A
[S
][0]<=X
) ansA
+=A
[S
][0];
}
ll ansA
,ansB
;
int main(){
n
=in();
for(int i
=1;i
<=n
;++i
) h
[i
]=in(),Map
[h
[i
]]=i
;
prework(),X0
=in(),m
=in();
double Min
=1e18;
for(int i
=1;i
<=n
;++i
){
calc(i
,X0
,ansA
,ansB
);
double now
=ansB
?1.0*ansA
/ansB
:1e18;
if(Min
>now
) Min
=now
,pos
=i
;
}
printf("%d\n",pos
);
while(m
--){
int S
=in(),X
=in();
calc(S
,X
,ansA
,ansB
),printf("%lld %lld\n",ansA
,ansB
);
}
return 0;
}