描述
小(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$行驶的路程总数。
输入格式
第一行包含一个整数$N$,表示城市的数目。
第二行有$N$个整数,每两个整数之间用一个空格隔开,依次表示城市$1$到城市$N$的海拔高度,即$H_1,H_2,……,H_n,$且每个$H_i$都是不同的。
第三行包含一个整数$X_0$。
第四行为一个整数$M$,表示给定$M$组$S_i$和$X_i$。
接下来的$M$行,每行包含$2$个整数$S_i$和$X_i$,表示从城市$S_i$出发,最多行驶$X_i$公里。
输出格式
输出共$M+1$行。
第一行包含一个整数$S_0$,表示对于给定的$X_0$,从编号为$S_0$的城市出发,小$A$开车行驶的路程总数与小$B$行驶的路程总数的比值最小。
接下来的$M$行,每行包含$2$个整数,之间用一个空格隔开,依次表示在给定的$S_i$和$X_i$下小$A$行驶的里程总数和小$B$行驶的里程总数。
提示
对于$30\%$的数据,有$1leq Nleq 20,1leq Mleq 20$;
对于$40\%$的数据,有$1leq Nleq 100,1leq Mleq 100$;
对于$50\%$的数据,有$1leq Nleq 100,1leq Mleq 1000$;
对于$70\%$的数据,有$1leq Nleq 1000,1leq Mleq 10000$;
对于$100\%$的数据,有$1leq Nleq 10^5,1leq Mleq 10^4,-10^9leq Hleq 10^9,0leq X_0leq 10^9,1leq S_ileq N,0leq Xileq 10^9$,数据保证$H_i$互不相同。
这道题是很久以前刷$noip$题的时候留下来未解决的,现在来填个坑……
一开始我写的是平衡树,现在看了$NOI$年鉴之后才意识到可以使用排序加链表来解决……
我们先考虑如果我们知道了每个位置往后最近的城市和次近的城市,那么我们可以使用倍增来解决这道题。我们处理出每个位置往后跳$2^i$所在的位置以及此时小$A$走过的距离和小$B$走过的距离,第二问的每个询问就可以在$O(log n)$的复杂度内得到解决。而第一位又可以枚举起点算一算,所以,我们主要是要找出每个点往后会走到哪儿。
当然,我们可以考虑从后往前扫一遍,那么我们需要支持的操作有两个:加入一个值,以及查询比某个值大的最小、次小值,比这个值小的最大、次大值。这样的话我们就需要一颗平衡树。虽然直接调用$set$即可解决,但是常数非常之大,我之前就在$vijos$上被卡$TLE$了一个点,并且死活过不去。
我们现在来考虑一种新的方法。其实这种方法在今年$noip$的初赛中就已经出现了。我们可以把所有的高度排好序,并且记录下原位置。然后,我们按照排序之后的顺序构建一个双向链表,按原顺序扫一遍。在这个双向链表中我们可以非常轻易地找出我们所需要的信息,并且每次用完这个点之后我们需要将它删除,在这个双向链表中也可以在常数复杂度内做到。所以,我们就没有必要使用平衡树了。
下面贴代码(代码有点丑):
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #include<cmath> #define File(s) freopen(s".in","r",stdin),freopen(s".out","w",stdout) #define maxn 100010 #define INF (1LL<<60) using namespace std; typedef long long llg; struct data{ llg x;int y; data(llg a=0,int b=0):x(a),y(b){} }a[5]; int wh[maxn],n,m,pr[maxn],ne[maxn],ns; int X,to[maxn][17],na[maxn],nb[maxn],fa[maxn],fb[maxn]; llg ca,cb,va[maxn][17],vb[maxn][17],h[maxn]; double now; int getint(){ int w=0;bool q=0; char c=getchar(); while((c>'9'||c<'0')&&c!='-') c=getchar(); if(c=='-') c=getchar(),q=1; while(c>='0'&&c<='9') w=w*10+c-'0',c=getchar(); return q?-w:w; } bool operator < (data x,data y){ if(x.x!=y.x) return x.x<y.x; return h[x.y]<h[y.y]; } void qsort(int l,int r){ int i=l,j=r,mid=h[wh[(l+r)>>1]]; while(i<=j){ while(h[wh[i]]<mid) i++; while(h[wh[j]]>mid) j--; if(i<=j) swap(wh[i++],wh[j--]); } if(i<r) qsort(i,r); if(j>l) qsort(l,j); } void pre(){ wh[n+1]=ne[n+1]=n+1; h[0]=-INF; h[n+1]=INF; for(int i=1;i<=n;i++) ne[wh[i]]=wh[i+1],pr[wh[i]]=wh[i-1]; for(int i=1;i<=n;i++){ a[1]=data(h[ne[i]]-h[i],ne[i]); a[2]=data(h[ne[ne[i]]]-h[i],ne[ne[i]]); a[3]=data(h[i]-h[pr[i]],pr[i]); a[4]=data(h[i]-h[pr[pr[i]]],pr[pr[i]]); if(pr[i]>=1) ne[pr[i]]=ne[i]; if(ne[i]<=n) pr[ne[i]]=pr[i]; sort(a+1,a+5); nb[i]=a[1].y%(n+1); na[i]=a[2].y%(n+1); fa[i]=a[2].x; fb[i]=a[1].x; } for(int i=1;i<=n;i++){ if(na[i]) va[i][0]=fa[i],to[i][0]=na[i]; if(nb[na[i]]) va[i][1]=va[i][0],vb[i][1]=fb[na[i]],to[i][1]=nb[na[i]]; } for(int j=2;j<=16;j++){ for(int i=1;i<=n;i++){ if(to[to[i][j-1]][j-1]){ va[i][j]=va[i][j-1]+va[to[i][j-1]][j-1]; vb[i][j]=vb[i][j-1]+vb[to[i][j-1]][j-1]; to[i][j]=to[to[i][j-1]][j-1]; } } } } double cal(){ if(!cb) return (1LL<<60); return (double)ca/(double)cb; } void solve(int S,int X){ ca=cb=0; for(int i=16;i>=0;i--) if(to[S][i] && ca+cb+va[S][i]+vb[S][i]<=X) ca+=va[S][i],cb+=vb[S][i],S=to[S][i]; } int main(){ File("a"); n=getint(); for(int i=1;i<=n;i++) h[i]=getint(),wh[i]=i; qsort(1,n); pre(); now=1e100; X=getint(); for(int i=1;i<=n;i++){ solve(wh[i],X); double x=cal(); if(x<=now) now=x,ns=wh[i]; } printf("%d ",ns); m=getint(); while(m--){ int s=getint(),x=getint(); solve(s,x); printf("%lld %lld ",ca,cb); } return 0; }
几个提交的地方:vijos P1780,codevs 1199