这不是一道决策选择题目,从每一个点出发,将要经过的路径除了受x值所影响而在长度有变化外,实际上是固定的,这个是倍增的基础
- 从一个节点到另一个节点的长度实则为两个节点权值之差,每个节点的最小点与次小点都位于该节点的右侧
- 题目可以分三部分解决,第一部分用于预处理每个节点右侧最小点与次小点,第二部分用于倍增预处理将时间负复杂度降为O(1),第三部分用于解决问题
**First part**
我采用的标记+Fenwick树+vector求解,可惜常数较大(正解双向链表,O(1)复杂度+极小常数)
- vector按顺序存入每个节点的ID和权值,然后以权值为比较对象进行排序
- 设某节点位置为i,易知每个点的最小点和次小点的位置位于[i-2, i+2] 这个区间中(假设该区间中的所有节点位于该节点的右侧)(当然不是该节点本身)
- 让我们从最左侧节点向右开始寻找,每次确认了最小点和次小点后就将它从vector中erase,即可保证每个节点寻找到的最小值都位于该节点的右侧
- 为了保证查找与erase是从1~n的,我们需要得到每个节点在vector中动态的位置,在这里我采用了Fenwick树获得动态位置
1. 将每个节点的初始位置进行标记,然后每次出vector便在该位置中Fenwick树增加值,值为1
2. 每次要查询某个点,该节点的动态位置为标记位置-标记位置前方已经erase掉的点
- 有一个小细节,当两点的距离相同时海拔较低而优先级高
**Second part**
采用倍增求解(倍增也为正解,也只有倍增为正解)
- 不难发现,从任意节点出发先由A开车,经过2的0次方个点后为B开车,经过2的1次方的点后为A开车,经过2的2次方的点后为A开车...以此类推不需要特判B开车的情况
- 开车经过的总距离为A开车的距离+B开车的距离,开两个数组分别记录即可
- 设可经过路程为X,进入递归函数进行模拟直到总路程最接近X位置
- 有一个小细节,路程可能会爆int所以要开long long
**Third part**
1. 枚举节点然后以X0为距离限制进行判断最优值
2. 取出预存好的查询内容进行查询
- 这一段的细节非常多
截取题面 对于一个给定的 X=X0从哪一个城市出发,小 A 开车行驶的路程总数与小 BB 行驶的路程总数的比值最小(**如果小 B 的行驶路程 0,此时的比值可视为无穷大,且两个无穷大视为相等**)。如果从多个城市出发,小 A 开车行驶的路程总数与小B行驶的路程总数的**比值都最小,则输出海拔最高的那个城市。**
```
#include<cstdio>
#include<iostream>
#include<cstring>
#include<cctype>
#include<algorithm>
#include<cmath>
#include<vector>
#include<time.h>
using namespace std;
inline int in();
inline void put(long long);
void gosearch(int);
void add(int x, int y);
int sum(int x);
int pit(int x) {return x&-x;}
struct Node{
int high, id;
Node (int a = 0, int b = 0) : high(a), id(b) {}
bool operator < (const Node& temp) const {
return high > temp.high;
}
};
const int INF = 2147483645;
vector <Node> k;
int n, M, X0;
int high[100100], Si[100100], Xi[100100], fir[100100], sec[100100], mem[100100], Fenwick[100100], maxn[100100];
int Go[100100][20]; long long goAlen[100100][20], goBlen[100100][20];
void go(int ind, long long& tA, long long& tB, int len) {
for (int j = maxn[ind]; j >= 0; --j) {
if (Go[ind][j]) {
if (tA+tB+goAlen[ind][j]+goBlen[ind][j] <= len) {
tA += goAlen[ind][j];
tB += goBlen[ind][j];
go(Go[ind][j], tA, tB, len);
break;
}
}
}
}
void work() {
sort(k.begin(), k.end());
int p = k.size();
for (int i = 0; i < p; ++i) {
mem[k[i].id] = i;
}
for (int i = 1; i <= n; ++i) {
gosearch(mem[i]-sum(mem[i]+1));
add(mem[i]+1, 1);
}
for (int i = n; i >= 1; --i) {
Go[i][0] = sec[i];
Go[i][1] = fir[sec[i]];
if (Go[i][0]) goAlen[i][0] = goAlen[i][1] = abs(high[i]-high[sec[i]]);
if (Go[i][1]) goBlen[i][1] = abs(high[sec[i]]-high[fir[sec[i]]]);
for (int j = 2; ; ++j) {
if (!Go[Go[i][j-1]][j-1]) {
maxn[i] = j-1;
break;
}
Go[i][j] = Go[Go[i][j-1]][j-1];
goBlen[i][j] = goBlen[Go[i][j-1]][j-1]+goBlen[i][j-1];
goAlen[i][j] = goAlen[Go[i][j-1]][j-1]+goAlen[i][j-1];
}
}
double eps = (double)INF;
int ans, maxhigh = -INF;
for (int i = 1; i <= n; ++i) {
long long tA = 0, tB = 0;
go(i, tA, tB, X0);
if (tB) {
double fps = 1.0*tA/tB;
if (fps <= eps) {
if (fps == eps) {
if (high[i] > maxhigh) {
maxhigh = high[i];
ans = i;
}
} else {
eps = fps;
ans = i;
maxhigh = high[i];
}
}
}
}
printf("%d\n", ans);
for (int i = 1; i <= M; ++i) {
long long tA = 0, tB = 0;
go(Si[i], tA, tB, Xi[i]);
printf("%lld %lld\n", tA, tB);
}//*//*
}
void input() {
n = in();
for (int i = 1; i <= n; ++i) {
high[i] = in();
k.push_back(Node(high[i], i));
}
X0 = in();
M = in();
for (int i = 1; i <= M; ++i) {
Si[i] = in(); Xi[i] = in();
}
}
int main() {
input();
work();
//printf("%.4lf", (double)clock()/CLOCKS_PER_SEC);
}
void gosearch(int i) {
int first = INF, second = INF, firx = 0, secx = 0, e = k[i].high, p = k.size();
bool flag1 = false, flag2 = false;
for (int j = i-2; j <= i+2; ++j) {
if (j < 0 or j == i or j >= p) continue;
if (abs(k[j].high-e) <= first) {
flag1 = true;
first = abs(k[j].high-e);
firx = k[j].id;
}
}
for (int j = i-2; j <= i+2; ++j) {
if (j < 0 or j == i or j >= p) continue;
if (abs(k[j].high-e) <= second and k[j].id != firx) {
flag2 = true;
second = abs(k[j].high-e);
secx = k[j].id;
}
}
if (flag1) fir[k[i].id] = firx;
if (flag2) sec[k[i].id] = secx;
k.erase(k.begin()+i);
}
void add(int x, int s) {
while (x <= n) {
Fenwick[x] += s;
x += pit(x);
}
}
int sum(int x) {
int tot = 0;
while (x > 0) {
tot += Fenwick[x];
x -= pit(x);
}
return tot;
}
inline int in() {
int ch = getchar(), x = 0, base = 1;
while (!isdigit(ch)) {
if (ch == '-') base = -1;
ch = getchar();
}
while (isdigit(ch)) x = x*10+ch-'0', ch = getchar();
return x*base;
}
```
转载于:https://www.cnblogs.com/NHDR233/p/11246744.html