题目描述 传送门
很容易想到
O(n2)
暴力预处理在每个城市时小A和小B分别要到达的另一个城市和距离。再暴力
O(nm)
求每一个询问。这样可以骗到70分。
预处理时可以用平衡树,具体操作是将每一座城市从西往东一个插入树,再寻找与它距离最近的,仔细想一下就知道怎么找了。因为是倒着插,所以树中的一定是此城市西边的。(平衡树可以用STL的set)
作为蒟蒻的我以前只知道倍增可以搞st表和树上lca,然而不知道倍增还可以这样用,看了网上的题解才晓得,看来我对倍增的理解还不够深刻。
至于倍增的地方自己可以YY出来(然而自从我学会树链剖分就没怎么用过倍增了,所以写了好久也写的好烂…)
纯自己写的(烂的话不要见笑)
代码
#include<cstdio>
#include<iostream>
#include<cstring>
#include<set>
#include<algorithm>
#include<climits>
#include<cmath>
#define INF INT_MAX-1
using namespace std;
const int maxn=100005;
typedef pair<int,int> pii;
set<pii>s;
int f[maxn][20][2],g[maxn][20],h[maxn],dist1[maxn],dist2[maxn],first[maxn],second[maxn],I;
bool cmp(const pii&a,const pii&b){
return abs(a.first-h[I])==abs(b.first-h[I])?a.first<b.first:abs(a.first-h[I])<abs(b.first-h[I]);
}
void getfs(int &i){
set<pii>::iterator itl=s.find(pii(h[i],i));
set<pii>::iterator itr=itl;
pii a[4];
int cnt=0;
if(itl--!=s.begin()){
a[cnt++]=*itl;
if(itl--!=s.begin()) a[cnt++]=*itl;
}
if(++itr!=s.end()){
a[cnt++]=*itr;
if(++itr!=s.end()) a[cnt++]=*itr;
}
I=i;
sort(a,a+cnt,cmp);
if(cnt<=1) dist2[i]=INF;
else{
dist2[i]=abs(a[1].first-h[i]);
second[i]=a[1].second;
}
if(cnt==0) dist1[i]=INF;
else{
dist1[i]=abs(a[0].first-h[i]);
first[i]=a[0].second;
}
}
int main(){
int n;
cin>>n;
for(int i=1;i<=n;i++) scanf("%d",&h[i]);
for(int i=n;i>0;i--){
s.insert(pii(h[i],i));
getfs(i);
}
for(int i=1;i<=n;i++){
g[i][0]=first[second[i]];
f[i][0][1]=dist2[i];
f[i][0][0]=dist1[second[i]];
}
for(int j=1;j<=19;j++)
for(int i=1;i<=n;i++){
g[i][j]=g[g[i][j-1]][j-1];
if(f[i][j-1][0]==INF||f[g[i][j-1]][j-1][0]==INF) f[i][j][0]=INF;
else f[i][j][0]=f[i][j-1][0]+f[g[i][j-1]][j-1][0];
if(f[i][j-1][1]==INF||f[g[i][j-1]][j-1][1]==INF) f[i][j][1]=INF;
else f[i][j][1]=f[i][j-1][1]+f[g[i][j-1]][j-1][1];
}
int X;
cin>>X;
double ansvalue=INF+1;
int ans;
for(int i=1;i<=n;i++){
int x=X,b=i,distA=0,distB=0;
for(int j=19;j>=0;--j) if(f[b][j][0]!=INF&&f[b][j][1]!=INF&&f[b][j][0]+f[b][j][1]<=x){
x-=f[b][j][0]+f[b][j][1];
distA+=f[b][j][1];
distB+=f[b][j][0];
b=g[b][j];
}
if(f[b][0][1]<=x) distA+=f[b][0][1];
double value;
if(distB==0) value=INF;
else value=1.0*distA/distB;
if(value<ansvalue||(fabs(value-ansvalue)<=1e-9&&h[ans]<h[i])) ansvalue=value,ans=i;
}
cout<<ans<<endl;
int m;
cin>>m;
for(int i=0;i<m;i++){
int b,x,distA=0,distB=0;
scanf("%d%d",&b,&x);
for(int j=19;j>=0;--j) if(f[b][j][0]!=INF&&f[b][j][1]!=INF&&f[b][j][0]+f[b][j][1]<=x){
x-=f[b][j][0]+f[b][j][1];
distA+=f[b][j][1];
distB+=f[b][j][0];
b=g[b][j];
}
if(f[b][0][1]<=x) distA+=f[b][0][1];
printf("%d %d\n",distA,distB);
}
return 0;
}