Subtask 1
In subtask 1, there are only two elephants. Thus we can easily determine the number of required cameras in constant time. Namely, we only need one camera if the elephants are at most distance
apart; otherwise, we need two cameras.
Subtasks 2 and 3
If elephants are at positions
, such that
for all
, we can compute the minimum number of cameras required using a greedy algorithm. We start with an empty set of cameras. While the current set of cameras do not cover all elephants, we choose an elephant which is not already covered with the minimum position
, and place a camera to cover elephants at positions in
. We can implement this procedure to run in time
by iterating through the list of sorted positions once.
Each time an elephant moves in the show, we can update the sorted list of positions in
time. Hence, we have an
solution to this problem, which is sufficient to fully solve subtask 2, and an adequate optimization is required to fully solve subtask 3. However, a faster algorithm is required for subtasks 4 and 5.
Subtasks 4 and 5
Bucketing elephants
To find the number of cameras, instead of iterating through all elephants, we shall build a data structure that allows us to "jump" over lots of elephants.
We maintain
buckets
of elephants such that buckets with lower indices store elephants with lower positions, i.e., for any
, for all
and
,
. Also, elephants in each bucket are sorted according to their positions.
The goal is to make sure that to find the number of required cameras, one needs to visit each bucket once. For simplicity, we will always place cameras so that the left-most position covered by a camera is the position of some elephant.
Consider bucket
with
elephants. Denote the list of indices of elephants in
as
(that is,
). Given an elephant
, we would like to answer the following two questions quickly:
- If we would like to cover all elephants starting from
(i.e., elephants in the set
), how many cameras are needed?
- What is the highest position that this set of cameras cover?
For elephant
, denote the answer for Q1 as
and the answer to Q2 as
.
If we have these answers for every elephant in every bucket, we can find the number of cameras in time
as follows.
We start by placing the camera at the first elephant in bucket
, so that the position of this elephant is the left-most position covered by this camera. Now consider placing a camera at elephant
in bucket
in the same fashion. We know that to cover all elephants in
, we have to use
cameras and these cameras cover positions up to
. We find the first elephant
not covered by these cameras in the next bucket
by binary searching for the elephant in
whose position is minimum but greater than
. Then, we start placing the camera at elephant
in bucket
.
We repeat this step until we reach the last bucket. Since each step runs in
time (from binary search), we spend
time as required.
We can precompute the answers for Q1 and Q2 for elephants in
in
time by iterating over each elephant
from
to
and keeping a pointer to the first elephant outside the range
. For implementation details, please see the appendix.
It is crucial to note that we can process each bucket independently of all other buckets.
Updating the data structure
When an elephant
moves, we will have to update two buckets: the current bucket
and the new bucket
. This can be done in time proportional to the current size of the bucket. To find the current bucket of
, we can store a pointer from
, but it takes
to find the new bucket anyway. Therefore, the running time for the update is
.
Note that the time depends heavily on the size of each bucket. Initially, we would have about
elephants in each bucket, but the number may grow as elephants can move. To keep the size of each bucket bounded above by
, we will rebuild the whole data structure for every
updates. The rebuilding takes time
.
Choosing the right parameter
We need to handle
updates and answer one question after each of these updates. The total running time is:

where the first term denotes the total query time, the second term denotes the total updating time, and the last term denotes the total rebuilding time.
Choosing
gives the running time of
, which is sufficient to obtain full marks for this problem. However, an inefficient implementation may not be able to solve subtask 5. For example, using the set
data structure in the C++ Standard Template Library can introduce an extra factor of
to the running time of rebuilding the data structure. This can be avoided by using simple arrays.
Appendix: Processing each bucket
To simplify the presentation, we add a dummy elephant
at position
. Also, we let
be the position of the
left-most elephant in bucket
.
We consider each elephant
from the right-most elephant
to the left-most one. We also maintain an index
that points to the left-most elephant
whose position
. Initially,
and
.
For each elephant
, we will compute
and
, the left-most elephant in the right-most camera in the set of cameras covering
.
For the dummy node, we let
and
. For elephant
, we check if we need to move
, i.e., if the position of
is greater than
; if that's the case we find the smallest
such that
. We let
and
.
Finally, for each elephant
such that
points to the dummy elephant
, we change
to
.
We can complete the process using only one pass over all elephants in the bucket
and note that the pointer
moves over each elephant only once. Thus, the running time is
as claimed.
To answer question Q2 for each elephant
, we report
.
Comments