游走

题目大意

一个街道上有$n$个路灯,编号$1,2,\dots, n$,酒鬼时刻$0$时在点$1$,从某个时间$t_0$开始游走,$t_0$时间之后,每隔一个单位时间会移动到相邻的路灯旁,不能不走,不能超过街道的边界。

$m$次操作,操作有三种类型:

1.告诉你信息,路人在时间$p$看到$q$。

2.询问$t_0$的最小值。

3.询问$t_0$的最大值。

如果路人给的信息有问题,后面的询问输出”bad”,如果最大值可以无限大,输出”inf”。

解题思路

首先,当有多个路人在同一时间看到酒鬼在不同的路灯位置,说明信息有误,接下来都输出”bad”。

这里位置$1$很特殊,我们知道从$t_0$当酒鬼开始游走后,路人看到的酒鬼相邻两次时间差与位置差的奇偶性必须一致,否则信息有误。这题的关键一点就是对于位置$1$出现了奇偶性不同的时间,应该按照第一次酒鬼不在位置$1$的最早时间来确定是否出现bad。

这里分类讨论以下,如果路人给的信息没有出现位置非$1$的情况,显然我的$t_0$可以取到无穷大,而$t_0$最小值应该对位置$1$的所有时间进行讨论,如果没有位置$1$,$t_0$最小取$0$,因为没有任何限制。而位置$1$的所有时间如果只有奇数,$t_0$最小可以取$1$,原因同样还是路人看到的酒鬼相邻两次时间差与位置差的奇偶性必须一致;偶数情况同理。如果位置$1$的所有时间既有奇数又有偶数,$t_0$取$min(最大的奇数,最大的偶数)+1$,这样开始游走后路人看到的位置$1$的所有时间一定是相同的奇偶性。

当路人给定信息出现位置非$1$的情况,那么$t_0$的最大值根据出现位置非$1$的最早时间决定,$t_0$最大情况一定是从$t_0$出发后向这个最早时刻的非$1$位置走,最小情况类似上一段分析。这里还有一种bad的情况要考虑从最大$t_0$开始的相邻两点位置差会不会大于时间差。

对于位置的维护可以用set<pair<int, int>>,维护路人给出的时间和位置。第一次出现位置非$1$对应的最早时间以前出现的位置$1$可以按照奇偶性用set<int>独立维护,这样前面的部分插入到set<pair<int, int>>需要满足相邻位置之差小于等于相邻时间之差并且奇偶性相同,前者用来找$t_0$的最值。

参考代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
#include<bits/stdc++.h>
using namespace std;

inline void work() {
set<pair<int,int> > st;
int mx = 2e9, pos = 2e9, last = -1;
bool ok = true;
int n, m;
cin >> n >> m;
while(m--) {
int op, p, q;
cin >> op;
if (op == 1) {
if (!ok) puts("bad");
else if (last != -1) {
auto ptr = st.lower_bound({last, 0});
if ((prev(ptr) -> first) == (ptr -> first) - 1) printf("%d\n", (ptr -> first));
else printf("%d\n", (prev(ptr) -> first) + 1);
} else {
if (st.size() == 0) puts("0");
else {
auto ptr = *st.begin();
printf("%d\n", (ptr.first + ptr.second + 1) % 2);
}
}
} else if (op == 2) {
if (!ok) puts("bad");
else if (mx == 2e9) puts("inf");
else printf("%d\n", mx);
} else {
cin >> p >> q;
if (abs(p - 1) > q) {ok = false; continue;}
if (p > 1) pos = min(pos, q);
if (p > 1) mx = min(mx, q - abs(p - 1));
st.insert({q, p});
auto ptr = st.find({q, p});
if (ptr != st.begin() && next(ptr) != st.end() && last == (next(ptr) -> first)) last = -1;
if (ptr != st.begin()) {
auto pre = *prev(ptr);
if ((pre.first + pre.second) % 2 != (p + q) % 2) last = max(last, q);
if (abs(pre.second - p) > abs(pre.first - q)) {ok = false; continue;}
}
if (next(ptr) != st.end()) {
auto nxt = *next(ptr);
if ((nxt.first + nxt.second) % 2 != (p + q) % 2) last = max(last, nxt.first);
if (abs(nxt.second - p) > abs(nxt.first - q)) {ok = false; continue;}
}
if (last > pos) {ok = false; continue;}
}
}
}

int main() {
cin.tie(0);
ios::sync_with_stdio(false);
int t; cin >> t;
while (t--) work();
return 0;
}