>Link
luogu P1081
ybtoj开车旅行
>Description
>解题思路
先预处理 n n n个点,从每一个点出发,最近的下个点和第二近的下个点
因为距离为两点的海拔高度差,那我们就可以先按照海拔高度排个序,那最近的点就在它的前驱和后驱之中,第二近的点就在前驱、后驱、前驱的前驱、后驱的后驱之中
那我们从 1 1 1到 n n n处理完一个点后,要把当前点删去,因为题目规定了后面的点不能到达前面的点
这个可以用双向链表维护,也可以用平衡树
(要注意是否越界QwQ)
对于第二个问题,由于必须先有一个 O ( n ) O(n) O(n),所以我们往 O ( n l o g n ) O(nlogn) O(nlogn)考虑
设两个数组倍增DP:
f i , j , 0 / 1 f_{i,j,0/1} fi,j,0/1:从第 i i i个点出发,走 2 j 2^j 2j步,小A / 小B 先走最后到达的终点
d i s i , j , 0 / 1 dis_{i,j,0/1} disi,j,0/1:从第 i i i个点出发,走 2 j 2^j 2j步,小A先走,小A / 小B走过的路程
然后我们DP就行了(转移方程还挺好推得,就设置状态不会QAQ)
然后我们按照题意处理就行了,最多走 x x x路程,那我们就倍增跳着走,在 x x x的限制下尽量走多的路程
>代码
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#define N 100010
#define inf 20000000000
#define LL long long
#define db long double
using namespace std;
struct node
{
int id, l, r;
LL h;
} a[N];
struct SUM
{
LL s1, s2;
};
int n, pos[N], to[N][5], f[N][30][5], dis[N][30][5], g;
int m, s, ans1;
LL w[N][5], H[N], x;
db ans;
bool cmp (node aa, node bb) {
return aa.h < bb.h;}
SUM solve (int s, int x) //从s出发,最多走x路程
{
LL s1 = 0, s2 = 0;
for (int j = 20; j >= 0; j--)
if (f[s][j][0] && s1 + s2 + dis[s][j][0] + dis[s][j][1] <= x)
{
s1 += dis[s][j][0];
s2 += dis[s][j][1];
s = f[s][j][0];
}
return (SUM){
s1, s2};
}
int main()
{
scanf ("%d", &n);
for (int i = 1; i <= n; i++)
{
scanf ("%lld", &H[i]);
a[i].h = H[i], a[i].id = i;
if (H[i] > H[ans1]) ans1 = i;
}
sort (a + 1, a + 1 + n, cmp);
for (int i = 1; i <= n; i++)
{
a[i].l = i - 1, a[i].r = i + 1;
pos[a[i].id] = i;
}
int m1, m2, p, l, r; LL mn1, mn2;
for (int i = 1; i <= n; i++)
{
m1 = m2 = 0, mn1 = mn2 = inf;
p = pos[i];
l = a[p].l, r = a[p].r;
if (a[r].h - a[p].h <= mn1 && r && r <= n)
m1 = r, mn1 = a[r].h - a[p].h;
if (a[p].h - a[l].h <= mn1 && l && l <= n)
m1 = l, mn1 = a[p].h - a[l].h;
if (a[a[r].r].h - a[p].h <= mn2 && a[r].r && a[r].r <= n)
m2 = a[r].r, mn2 = a[a[r].r].h - a[p].h;
if (a[r].h - a[p].h <= mn2 && r != m1 && r && r <= n)
m2 = r, mn2 = a[r].h - a[p].h;
if (a[p].h - a[l].h <= mn2 && l != m1 && l && l <= n)
m2 = l, mn2 = a[p].h - a[l].h;
if (a[p].h - a[a[l].l].h <= mn2 && a[l].l && a[l].l <= n)
m2 = a[l].l, mn2 = a[p].h - a[a[l].l].h;
to[i][0] = a[m1].id, to[i][1] = a[m2].id;
w[i][0] = mn1, w[i][1] = mn2;
a[a[p].l].r = a[p].r, a[a[p].r].l = a[p].l;
// printf ("%d %lld %d %lld\n", to[i][0], w[i][0], to[i][1], w[i][1]);
}
// A->2nd B->1st
for (int i = n; i >= 1; i--)
{
f[i][0][0] = to[i][1];
f[i][0][1] = to[i][0];
f[i][1][0] = to[f[i][0][0]][0];
f[i][1][1] = to[f[i][0][1]][1];
dis[i][0][0] = dis[i][1][0] = w[i][1];
dis[i][0][1] = 0;
dis[i][1][1] = w[f[i][0][0]][0];
for (int j = 2; j <= 20; j++)
{
f[i][j][0] = f[f[i][j - 1][0]][j - 1][0];
dis[i][j][0] = dis[i][j - 1][0] + dis[f[i][j - 1][0]][j - 1][0];
f[i][j][1] = f[f[i][j - 1][1]][j - 1][1];
dis[i][j][1] = dis[i][j - 1][1] + dis[f[i][j - 1][0]][j - 1][1];
}
}
scanf ("%lld", &x);
ans = inf, ans1 = 0;
LL sum1, sum2;
SUM g;
for (int i = 1; i <= n; i++)
{
g = solve (i, x);
sum1 = g.s1, sum2 = g.s2;
if (sum1 == sum2 && sum1)
{
if (ans > (db)1) ans = (db)1, ans1 = i;
else if (ans == (db)1 && H[ans1] < H[i]) ans1 = i;
}
else if (sum2)
{
if (ans > (db)sum1 / (db)sum2)
ans = (db)sum1 / (db)sum2, ans1 = i;
else if (ans == (db)sum1 / (db)sum2 && H[ans1] < H[i])
ans1 = i;
}
}
printf ("%d\n", ans1);
scanf ("%d", &m);
while (m--)
{
scanf ("%d%lld", &s, &x);
g = solve (s, x);
printf ("%lld %lld\n", g.s1, g.s2);
}
return 0;
}