第一步预处理出来每个城市最近的城市和第二近的城市,这一步怎么做呢?先按高度排序
O
(
n
l
o
g
n
)
O(nlogn)
O(nlogn),再以排序后的元素建一个双向链表。这样按照原来读入的顺序枚举每个元素,找枚举元素的左一位,左两位,右一位,右两位这四个元素,如果出现没有某个元素的情况特判一下即可。枚举完一个元素就删除一个元素,这样保证双向链表中的元素在读入顺序中都是在枚举的元素的右边(或者是它本身)。这样我们就用
O
(
n
l
o
g
n
−
n
)
O(nlogn-n)
O(nlogn−n)找出了每个元素右边最大值和次大值以及它们的位置。
第二步我们预处理出来三个
S
T
ST
ST表。我们把a走一步和b走一步的操作合并到一起,视为操作了一步。开三个数组
t
[
i
]
[
j
]
,
S
T
a
[
i
]
[
j
]
,
S
T
b
[
i
]
[
j
]
t[i][j],STa[i][j],STb[i][j]
t[i][j],STa[i][j],STb[i][j]。
t
[
i
]
[
j
]
t[i][j]
t[i][j]表示从i号城市走,a和b分别走了
2
j
2^j
2j步,会到的城市的编号。
S
T
a
[
i
]
[
j
]
STa[i][j]
STa[i][j]表示从i号城市走,a和b分别走了
2
j
2^j
2j步,a在路上开的路程总数。
S
T
b
[
i
]
[
j
]
STb[i][j]
STb[i][j]表示从i号城市走,a和b分别走了
2
j
2^j
2j步,b在路上开的路程总数。
第三步就是解决问题的过程。非常简单的跑一下倍增的就好了。
这样我们利用倍增思想,在
O
(
n
l
o
g
n
−
n
−
m
l
o
g
n
)
O(nlogn-n-mlogn)
O(nlogn−n−mlogn)就是
O
(
(
n
+
m
)
l
o
g
n
)
O((n+m)logn)
O((n+m)logn)时间复杂度解决了本题。
#include<cstdio>
#include<cstring>
#include<vector>
#include<queue>
#include<stack>
#include<algorithm>
using namespace std;
#define IL inline
typedef long long LL;
const int N = 1e5 + 3;
const int INF = 1e9 + 3;
const int LOG = 20;
struct Node{
int h,p,l,r;
bool operator < (const Node& rhs) const {
return h < rhs.h || (h==rhs.h && p < rhs.p);
}
Node(int h=0,int p=0,int l=0,int r=0):h(h),p(p),l(l),r(r){}
};
struct Node1{
int p,v,h;
bool operator < (const Node1& rhs) const {
return v < rhs.v || (v == rhs.v && h < rhs.h);
}
Node1(int p=0,int v=0,int h=0):p(p),v(v),h(h) {}
};
int n,m,s,log;
LL x, suma = 0, sumb = 0;
double minans = INF<<1;
int h[N],pos[N],ta[N],tb[N],da[N],db[N];
Node aa[N];
int t[N][LOG];
LL STa[N][LOG],STb[N][LOG];
IL void init() {
scanf("%d",&n);
for(int i=1;i<=n;i++) scanf("%d",&h[i]);
for(int i=1;i<=n;i++) aa[i] = Node(h[i],i,0,0);
sort(aa+1,aa+1+n);
for(int i=1;i<=n;i++) aa[i].l = i-1, aa[i].r = i+1;
aa[1].l = aa[n].r = aa[0].l = aa[0].r = 0;
for(int i=1;i<=n;i++) pos[aa[i].p] = i;
for(int i=1;i<n;i++) {
//get ta[i],tb[i],da[i],db[i]
Node1 a[5]; int cnt=0;
int p[] = {aa[pos[i]].l,aa[pos[i]].r,aa[aa[pos[i]].l].l,aa[aa[pos[i]].r].r};
for(int j=0;j<4;j++) if(p[j]) {
a[cnt++] = Node1(aa[p[j]].p,abs(aa[p[j]].h-aa[pos[i]].h),aa[p[j]].h);
}
sort(a,a+cnt);
tb[i] = a[0].p; db[i] = a[0].v;
if(i == n-1) continue;
ta[i] = a[1].p; da[i] = a[1].v;
//delete i.
aa[aa[pos[i]].l].r = aa[pos[i]].r;
aa[aa[pos[i]].r].l = aa[pos[i]].l;
}
//get t[i][0] & STa[i][0] & STb[i][0].
for(int i=1;i<=n;i++) {
t[i][0] = tb[ta[i]];
STa[i][0] = da[i];
STb[i][0] = db[ta[i]];
}
// get all of the ST table.
for(int j=1;(1<<j)<=n;j++) {
for(int i=1;i+(1<<j)-1<=n;i++) {
t[i][j] = t[t[i][j-1]][j-1];
STa[i][j] = STa[i][j-1] + STa[t[i][j-1]][j-1];
STb[i][j] = STb[i][j-1] + STb[t[i][j-1]][j-1];
}
}
//debug
/*printf("ta[i]=\n");
for(int i=1;i<=n;i++) printf("%d ",ta[i]);
printf("\n");
printf("tb[i]=\n");
for(int i=1;i<=n;i++) printf("%d ",tb[i]);
printf("\n");
printf("t[i][j]=\n");
for(int i=1;i<=n;i++) {
for(int j=0;i+(1<<j)-1<=n;j++) {
printf("%d ",t[i][j]);
}
printf("\n");
}
printf("STa[i][j]=\n");
for(int i=1;i<=n;i++) {
for(int j=0;i+(1<<j)-1<=n;j++) {
printf("%d ",STa[i][j]);
}
printf("\n");
}
printf("STb[i][j]=\n");
for(int i=1;i<=n;i++) {
for(int j=0;i+(1<<j)-1<=n;j++) {
printf("%d ",STb[i][j]);
}
printf("\n");
}
printf("\n");*/
}
IL void get_suma_sumb(int p) {
suma = sumb = 0;
for(int j=log;j>=0;j--) {
if(t[p][j] && STa[p][j]+STb[p][j]+suma+sumb <= x) {
suma += STa[p][j];
sumb += STb[p][j];
p = t[p][j];
}
}
if(ta[p] && STa[p][0]+suma+sumb <= x) suma += STa[p][0];
}
IL void solve() {
//problem 1
scanf("%lld%d",&x,&m);
int ans = n; minans = INF<<1;
for(log=0;(1<<log)<=n;log++); log--;
for(int i=1;i<=n;i++) {
get_suma_sumb(i);
if(sumb && 1.0 * suma / sumb < minans) {
minans = 1.0 * suma / sumb;
ans = i;
}
}
printf("%lld\n",ans);
//problem 2
while(m--) {
scanf("%d%lld",&s,&x);
get_suma_sumb(s);
printf("%lld %lld\n",suma,sumb);
}
}
int main() {
init();
solve();
return 0;
}