[vijos1780][NOIP2012]开车旅行
作者:互联网
Description
小A和小B决定利用假期外出旅行,他们将想去的城市从1到N编号,且编号较小的城市在编号较大的城市的西边,已知各个城市的海拔高度互不相同,记城市i的海拔高度为\(H_i\),城市\(i\)和城市\(j\)之间的距离\(d[i,j]\)恰好是这两个城市海拔高度之差的绝对值,即\(d[i,j] = |H_i - H_j|\)。
旅行过程中,小A和小B轮流开车,第一天小A开车,之后每天轮换一次。他们计划选择一个城市S作为起点,一直向东行驶,并且最多行驶\(X\)公里就结束旅行。小A和小B的驾驶风格不同,小B总是沿着前进方向选择一个最近的城市作为目的地,而小A总是沿着前进方向选择第二近的城市作为目的地(注意:本题中如果当前城市到两个城市的距离相同,则认为离海拔低的那个城市更近)。如果其中任何一人无法按照自己的原则选择目的城市,或者到达目的地会使行驶的总距离超出\(X\)公里,他们就会结束旅行。
在启程之前,小A想知道两个问题:
1.对于一个给定的\(X=X_0\),从哪一个城市出发,小A开车行驶的路程总数与小B行驶的路程总数的比值最小(如果小B的行驶路程为\(0\),此时的比值可视为无穷大,且两个无穷大视为相等)。如果从多个城市出发,小A开车行驶的路程总数与小B行驶的路程总数的比值都最小,则输出海拔最高的那个城市。
2. 对任意给定的\(X=X_i\) 和出发城市\(S_i\),小A开车行驶的路程总数以及小B行驶的路程总数。
HINT
\(1≤N≤10^5,1≤M≤10^4,-10^9≤H_i≤10^9,0≤X_0≤10^9,1≤S_i≤N,0≤X_i≤10^9\),保证\(H_i\)互不相同.
Solution
预处理出从每个城市出发距离第一小和第二小的城市.
\(f[i][j]\)表示从\(i\)出发,走\(2^j\)轮到达的城市.
\(g1[i][j]\)表示从\(i\)出发,走\(2^j\)轮小A走的路程.
\(g2[i][j]\)表示从\(i\)出发,走\(2^j\)轮小B走的路程.
倍增求解即可.
#define K 18
#define N 100005
#define INF 1000000005
typedef long long ll;
struct city{
int h,x;
}h[N];
int f[N][K],g1[N][K],g2[N][K],nxt1[N],nxt2[N],n,m;
set<city> s;
set<city>::iterator xx;
bool operator < (city x,city y){
if(x.h!=y.h) return x.h<y.h;
return x.x<y.x;
}
//x比y优
inline bool cmp(int u,int x,int y){
if(!x) return false;
if(!y) return true;
if(abs(h[x].h-h[u].h)!=abs(h[y].h-h[u].h))
return abs(h[x].h-h[u].h)<abs(h[y].h-h[u].h);
return h[x].h<h[y].h;
}
inline int dis(int x,int y){
if(x&&y)
return abs(h[x].h-h[y].h)<INF?abs(h[x].h-h[y].h):INF;
return INF;
}
inline void drive(int u,int x,int &d1,int &d2){
int i;d1=d2=0;
while(x){
for(i=K-1;i>=0&&g1[u][i]+g2[u][i]>x;--i);
if(i<0) return;
x-=(g1[u][i]+g2[u][i]);
d1+=g1[u][i];d2+=g2[u][i];
u=f[u][i];
}
}
inline bool cmp2(int j,int k,int d1,int d2,int i,int id){
if(d1<0) return true;
if(d2&&k) return 1ll*j*d2<1ll*d1*k||(1ll*j*d2==1ll*d1*k&&h[i].h>h[id].h);
if(d2||k) return k;
return h[i].h>h[id].h;
}
inline void Aireen(){
n=read();
for(int i=1;i<=n;++i)
h[i].h=-read(),h[i].x=i;
city c1,c2;
s.clear();
for(int i=n-1;i;--i){
s.insert(h[i+1]);
c1=(*s.upper_bound(h[i]));
if(s.count(c1)){
s.erase(c1);
c2=(*s.upper_bound(h[i]));
s.insert(c1);
nxt1[i]=c1.x;nxt2[i]=c2.x;
}
else continue;
}
s.clear();
for(int i=1;i<=n;++i)
h[i].h=-h[i].h;
for(int i=n-1;i;--i){
s.insert(h[i+1]);
c1=(*s.upper_bound(h[i]));
if(s.count(c1)){
s.erase(c1);
c2=(*s.upper_bound(h[i]));
s.insert(c1);
if(cmp(i,c1.x,nxt1[i])){
nxt2[i]=nxt1[i];
nxt1[i]=c1.x;
if(s.count(c2)&&cmp(i,c2.x,nxt2[i]))
nxt2[i]=c2.x;
}
else if(cmp(i,c1.x,nxt2[i]))
nxt2[i]=c1.x;
}
else continue;
}
for(int j=0;j<K;++j)
g1[n][j]=g2[n][j]=g1[0][j]=g2[0][j]=INF;
for(int i=n-1;i;--i){
f[i][0]=nxt2[i];
f[i][1]=nxt1[nxt2[i]];
g1[i][0]=g1[i][1]=dis(i,nxt2[i]);
g2[i][1]=dis(nxt2[i],nxt1[nxt2[i]]);
for(int j=2;j<K;++j){
f[i][j]=f[f[i][j-1]][j-1];
g1[i][j]=g1[i][j-1]+g1[f[i][j-1]][j-1];
if(g1[i][j]>INF) g1[i][j]=INF;
g2[i][j]=g2[i][j-1]+g2[f[i][j-1]][j-1];
if(g2[i][j]>INF) g2[i][j]=INF;
}
}
int u,x,d1=-1,d2,id;
x=read();
for(int i=1,j,k;i<=n;++i){
drive(i,x,j,k);
if(cmp2(j,k,d1,d2,i,id)) d1=j,d2=k,id=i;
}
printf("%d\n",id);
m=read();
while(m--){
u=read();x=read();
drive(u,x,d1,d2);
printf("%d %d\n",d1,d2);
}
}
2017-10-27 13:30:24
标签:vijos1780,旅行,路程,NOIP2012,10,int,城市,行驶,g2 来源: https://www.cnblogs.com/AireenYe/p/15600163.html