题解:P14387 [JOISC 2017] 火车旅行 / Railway Trip
思路
问题需要我们最小化停靠站数量,那我们可以思考:对于每一个站点,在一个站点都不停靠的情况下,往左走最远可以走到哪个站点,往右走最远可以走到哪个站点。
设上面两个要求的量为
所以对于任意两个站点间的来往,一次停靠即可视作在
为什么要取最大和最小呢?因为一直往一个方向走不一定就是最优的(如样例 1 第二个询问的最优解)。还可以这样理解:区间
预处理出
代码
::::success[AC]
#include<bits/extc++.h>
using namespace std;
const int N=1e5+10,L=20;
int n,k,q;
int a[N];
int lim;
int l[N][L],r[N][L];
void Init(){
stack<int> stk;
for(int i=1;i<=n;++i){
while(stk.size()&&a[stk.top()]<a[i]) stk.pop();
l[i][0]=stk.size()?stk.top():i;
stk.push(i);
}
while(stk.size()) stk.pop();
for(int i=n;i>=1;--i){
while(stk.size()&&a[i]>a[stk.top()]) stk.pop();
r[i][0]=stk.size()?stk.top():i;
stk.push(i);
}
lim=log2(n)+1;
for(int j=1;j<=lim;++j){
for(int i=1;i<=n;++i){
l[i][j]=min(l[l[i][j-1]][j-1],l[r[i][j-1]][j-1]);
r[i][j]=max(r[l[i][j-1]][j-1],r[r[i][j-1]][j-1]);
}
}
}
int main(){
ios::sync_with_stdio(0);
cin.tie(0);
cin>>n>>k>>q;
for(int i=1;i<=n;++i) cin>>a[i];
Init();
while(q--){
int res=0,st,ed; cin>>st>>ed;
if(st>ed) swap(st,ed);
int x=st,y=st;
for(int i=lim;i>=0;--i){
int nx=min(l[x][i],l[y][i]),ny=max(r[x][i],r[y][i]);
if(ny<ed){
x=nx; y=ny;
res+=(1<<i);
}
}
int u=ed,v=ed;
for(int i=lim;i>=0;--i){
int nu=min(l[u][i],l[v][i]),nv=max(r[u][i],r[v][i]);
if(y<nu){
u=nu; v=nv;
res+=(1<<i);
}
}
cout<<res<<"\n";
}
return 0;
}
::::