走亲戚
题目链接:luogu U137972
题目大意
给你一个数轴,上面有 n 个点,然后每次给你起点的点和走的路径,问你最后会到哪个点。
走的方法:先向右走,走到不能走了(没油走到下一个点或者下面没有点了),就往左(也是走到不能走),然后继续向左,然后不停重复,直到两边都走不了。
思路
考虑其实可以暴力走,不过你一走就走到要掉头的部分。
那至于怎么走到掉头的部分我们可以二分得到。(这里我直接用 lower_bound upper_bound)
但你会发现它可能在两个点之间反复横跳一段距离,如果次次都算就会 T,那这个我们可以用取模弄掉。(记得判断在最后的方向)
至于为什么这样暴力走是可以过的呢?
我们首先看看别的复杂度,询问
m
m
m,二分
l
o
g
n
logn
logn。
然后你想,你跑过去跑回来就模掉,跑过去跑不动了跑回来,那你跑回来的是不会超过你本来要跑过去那个点的距离的。
那这个长度就直接减半(因为你原本跑过你跑回来的距离)了。
所以是
l
o
g
1
0
9
log10^9
log109。
所以总的复杂度是 m l o g n l o g 1 0 9 mlognlog10^9 mlognlog109 可以过。
代码
#include<cstdio>
#include<algorithm>
#define ll long long
using namespace std;
struct home {
ll x;
int pl;
}a[200001];
int n, m, x, pl[200001], ans;
ll rd, y, q[200001];
bool cmp(home x, home y) {
return x.x < y.x;
}
int work(int l, int r, int pl, ll x, bool op) {
if (l == r) return a[l].pl;
if (op) {//往右走
if (a[r].x - a[pl].x <= x) {//先走到最右边
x -= a[r].x - a[pl].x;//处理反复横跳
x %= 2 * (a[r].x - a[l].x);
if (x < a[r].x - a[l].x) {//最后一步是往右还是往左
ans = lower_bound(q + l, q + r + 1, a[r].x - x) - q;
return work(ans, r, ans, x - (a[r].x - a[ans].x), 1);
}
else {
x -= a[r].x - a[l].x;
ans = upper_bound(q + l, q + r + 1, a[l].x + x) - q;
ans--;
return work(l, ans, ans, x - (a[ans].x - a[l].x), 0);
}
}
else {//走不到最右边
ans = upper_bound(q + l, q + r + 1, a[pl].x + x) - q;
ans--;
return work(l, ans, ans, x - (a[ans].x - a[pl].x), 0);
}
}
else {//往左走
if (a[pl].x - a[l].x <= x) {//先走到最左边
x -= a[pl].x - a[l].x;//处理反复横跳
x %= 2 * (a[r].x - a[l].x);
if (x < a[r].x - a[l].x) {//最后一步使往左还是往右
ans = upper_bound(q + l, q + r + 1, a[l].x + x) - q;
ans--;
return work(l, ans, ans, x - (a[ans].x - a[l].x), 0);
}
else {
x -= a[r].x - a[l].x;
ans = lower_bound(q + l, q + r + 1, a[r].x - x) - q;
return work(ans, r, ans, x - (a[r].x - a[ans].x), 1);
}
}
else {//走不到最左边
ans = lower_bound(q + l, q + r + 1, a[pl].x - x) - q;
return work(ans, r, ans, x - (a[pl].x - a[ans].x), 1);
}
}
}
int main() {
scanf("%d %d", &n, &m);
for (int i = 1; i <= n; i++) scanf("%lld", &a[i].x), a[i].pl = i;
sort(a + 1, a + n + 1, cmp);
for (int i = 1; i <= n; i++)
pl[a[i].pl] = i, q[i] = a[i].x;
rd = a[n].x - a[1].x;
while (m--) {
scanf("%d %lld", &x, &y);
printf("%d\n", work(1, n, pl[x], y, 1));
}
return 0;
}