『湖南省队集训』永不落幕的zy

题目

背景

人们的感情像洪水一样袭来,头晕目眩。

题目描述

zy 是一位拥有“共感”能力的少年,他总是能有意无意地感知别人的心情。 sm 是一位有着“心墙”的少女,她的感情无法传递出去。就像命运一般,他们相遇了,仿佛 zy(的能力)就是为了 sm 而存在一样(事实上也确实如此)。

sm 的心墙由许多迷茫组成,每个迷茫都希望从$X$轴上某一点去到另一点,而只有 zy 能消除 sm 的迷茫。面对数量如此庞大的迷茫, zy 不曾想要放弃,但有些迷失了方向。

假设现在时间是$0$, zy 在心墙的$1$位置, zy 每单位时间的移动速度是$1$。

若现在 zy 携带的迷茫想要去的地点和心墙上剩下的迷茫中在他右边的个数大于等于左边,则 zy 会向右移动,反之向左。若现在 sm 没有任何迷茫,则 zy 原地不动。现在 zy 想
知道,组成心墙的每个迷茫分别在什么时候消失。

为了尽快地让 zy 能拥抱 sm,请你帮帮他。

输入描述

第一行两个数$N, M$表示迷茫的数量和心墙的大小。接下来$N$行,每行$3$个整数,$t, a, b$,表示这个迷茫出现在时刻$t$,希望从$a$到$b$。

输出描述

$N$行$N$个整数,表示每个迷茫分别在什么时候消失。

样例输入

2 10
1 2 5
7 4 5

样例输出

5
9

样例解释

时刻$1$,有迷茫出现了!

时刻$2$, zy 移动到了位置$2$。

时刻$5$, zy 移动到了位置$5$,迷茫消失。

时刻$7$,有迷茫出现了!

时刻$8$, zy 移动到了位置$4$。

时刻$9$, zy 移动到了位置$5$,迷茫消失。

数据范围

对于$30\%$的数据,$N, M, t \leq 100$;

对于$60\%$的数据,$N, M, t \leq 10000$;

对于$100\%$的数据,$N, M, t \leq 100000$。

后记

我们的落幕,是新的开始。

附件



题解

题意非常的玄妙,形象地说,就是公交车在路上跑,一段时间后会出现一个指定出发地和目的地的乘客,如果公交车右边的未上车乘客的出发地个数和车上乘客的目的地个数之和大于等于左边的,那就往右跑,否则往左跑,注意这是实时更新的,每出现一位乘客或一位乘客下车都可能导致方向改变。然后求每位乘客下车时间。

用线段树记录所有迷茫的位置,支持插入,删除(注意如果是乘客上车的话还要再插入一个目的地,要区分上下车的情况),区间内点数询问,求前驱后继,注意实现细节,特别是对于事件点重合的情况要非常小心。这样按照题意模拟运动就好,当然一次不止运动一个单位,在事件点不变的情况下能走多远走多远。

代码

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
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
#include <cstdio>
#include <cctype>
#include <cmath>
#include <algorithm>
#include <vector>
using namespace std;
#define MAXN 100010
int readint()
{
int x = 0, c;
while (!isdigit(c = getchar()));
do
x = x * 10 + c - '0';
while (isdigit(c = getchar()));
return x;
}
int n, m;
struct mimang
{
long long t;
int a, b, id;
mimang() {}
mimang(long long t, int a, int b, int id) : t(t), a(a), b(b), id(id) {}
};
bool operator <(mimang x, mimang y)
{
if (x.t != y.t)
return (x.t < y.t);
if (x.a != y.a)
return (x.a < y.a);
if (x.b != y.b)
return (x.b < y.b);
return (x.id < y.id);
}
mimang q[MAXN];
struct node
{
int sum, minpos, maxpos, l, r;
vector<int> ms;
node () {}
node(int l, int r) : l(l), r(r), sum(0), minpos(200100), maxpos(0) {}
};
node segtree[MAXN << 2];
inline void update(int x)
{
segtree[x].sum = segtree[x << 1].sum + segtree[(x << 1) | 1].sum;
segtree[x].minpos = min(segtree[x << 1].minpos, segtree[(x << 1) | 1].minpos);
segtree[x].maxpos = max(segtree[x << 1].maxpos, segtree[(x << 1) | 1].maxpos);
}
void build(int now, int l, int r)
{
segtree[now] = node(l, r);
if (l < r)
{
int mid = l + (r - l) / 2;
build(now << 1, l, mid);
build((now << 1) | 1, mid + 1, r);
}
}
int query(int now, int l, int r)
{
int nl = segtree[now].l, nr = segtree[now].r;
if (l <= nl && r >= nr)
return segtree[now].sum;
if (l > nr || r < nl)
return 0;
return query(now << 1, l, r) + query((now << 1) | 1, l, r);
}
void insert(int now, int pos, int id)
{
int nl = segtree[now].l, nr = segtree[now].r;
if (nl == nr)
{
segtree[now].sum++;
segtree[now].minpos = segtree[now].maxpos = nl;
segtree[now].ms.push_back(id);
return;
}
int mid = nl + (nr - nl) / 2;
if (pos <= mid)
insert(now << 1, pos, id);
else
insert((now << 1) | 1, pos, id);
update(now);
}
int workl(int now, int pos)
{
int nl = segtree[now].l, nr = segtree[now].r;
if (nl == nr)
return segtree[now].maxpos;
int mid = nl + (nr - nl) / 2;
if (pos <= mid)
return workl(now << 1, pos);
else
return max(workl(now << 1 | 1, pos), segtree[now << 1].maxpos);
}
int workr(int now, int pos)
{
int nl = segtree[now].l, nr = segtree[now].r;
if (nl == nr)
return segtree[now].minpos;
int mid = nl + (nr - nl) / 2;
if (pos <= mid)
return min(workr(now << 1, pos), segtree[(now << 1) | 1].minpos);
else
return workr((now << 1) | 1, pos);
}
long long now, pos;
long long time, ans[MAXN];
int cnt;
void clear(int now, int pos)
{
int nl = segtree[now].l, nr = segtree[now].r;
if (nl == nr)
{
for (int i = 0; i < (int)segtree[now].ms.size(); i++)
{
int v = segtree[now].ms[i];
if (v > 0)
insert(1, q[v].b, -v);
else
ans[q[-v].id] = time, cnt++;
}
segtree[now].ms.clear();
segtree[now] = node(pos, pos);
return;
}
int mid = nl + (nr - nl) / 2;
if (pos <= mid)
clear(now << 1, pos);
else
clear((now << 1) | 1, pos);
update(now);
}
int main()
{
freopen("sm.in", "r", stdin);
freopen("sm.out", "w", stdout);
n = readint();
m = readint();
for (int i = 1; i <= n; i++)
{
int t = readint();
int a = readint();
int b = readint();
q[i] = mimang(t, a, b, i);
}
cnt = 0, now = 1, time = 0, pos = 0;
sort(q + 1, q + n + 1);
build(1, 1, m);
while (cnt < n)
{
if (query(1, 1, m) == 0)
{
if (pos == n)
break;
time = q[pos + 1].t;
pos++;
while (pos <= n && q[pos].t == time)
{
insert(1, q[pos].a, pos);
pos++;
}
pos--;
}
else
{
int left = query(1, 1, now - 1);
int right = query(1, now + 1, m);
long long ls;
if (right >= left)
ls = workr(1, now);
else
ls = workl(1, now);
if (pos == n || time + abs(now - ls) <= q[pos + 1].t)
{
time = time + abs(now - ls);
now = ls;
clear(1, ls);
if (time == q[pos + 1].t)
{
pos++;
while (pos <= n && q[pos].t == time)
{
insert(1, q[pos].a, pos);
pos++;
}
pos--;
}
}
else
{
pos++;
if (right >= left)
now += q[pos].t - time;
else
now -= q[pos].t - time;
time = q[pos].t;
while (pos <= n && q[pos].t == time)
{
insert(1, q[pos].a, pos);
pos++;
}
pos--;
}
}
}
for (int i = 1; i <= n; i++)
printf("%lld\n", ans[i]);
return 0;
}
文章目录
  1. 1. 题目
    1. 1.1. 背景
    2. 1.2. 题目描述
    3. 1.3. 输入描述
    4. 1.4. 输出描述
    5. 1.5. 样例输入
    6. 1.6. 样例输出
    7. 1.7. 样例解释
    8. 1.8. 数据范围
    9. 1.9. 后记
    10. 1.10. 附件
  2. 2. 题解
  3. 3. 代码
,