Editorial for COCI '20 Contest 6 #4 Geometrija
Submitting an official solution before solving the problem yourself is a bannable offence.
The first subtask can be solved in complexity by simply checking for each segment if it crosses with other segments.
To check if two segments cross, we will use the function
This is equal to twice the signed area of the triangle (which is not important in this task), and is positive when
,
and
are in counterclockwise order (ccw order for short).
Segments and
cross if and only if
(since the points are in general position in this task, we don't have to deal with special cases that would arise if some three were collinear). The proof is left as an exercise to the reader.
We say a segment is good if it doesn't cross with any other segment. For the rest of the solution, we use the observation that every good segment necessarily belongs to every triangulation of the given set of points. Triangulation of some set of points on the plane is a division of the convex hull into triangles with vertices in given points, such that every point is a vertex of at least one triangle. Equivalently, it is a maximal set of non-crossing segments between the given points. A triangulation can have at most segments, so if we find some triangulation, we get just
candidates for good segments. The proof of the claims above is left as an exercise to the reader.
Therefore, the second subtask can be solved in complexity. We can build a triangulation in
by going through all the segments, checking if it crosses with the already added segments, and if not, we add it to the triangulation. We then check for every segment we added, in
complexity, if it crosses with each possible segment.
We will solve the third subtask in complexity . Finding a triangulation is the easy part. There is a lot of ways to do it, fastest in complexity
, but we will describe an easier algorithm with
complexity. First, we find the convex hull, and triangulate that polygon in some way (for example by taking all diagonals from some point). Then, we go through all interior points, find the triangle that contains the current point, and divide it into three smaller triangles.
Now we describe how to check in complexity if some segment is good. Consider a segment
. To make it easier to describe the solution, imagine without loss of generality that the line
is vertical and
is above
, as in the figure below. Let
be all other points, in ccw order around
, so that for all
it holds
, and for all
it holds
(see the figure).
Consider some point . Let
be the maximum
such that
(if it exists). Points
are exactly those points on the right side that are below the line
. It's easy to see that
is increasing, so it can be calculated using the two pointers method.
Consider the ccw order of points around
(where we take the first point to be the one with maximum angle
). Let
be the position of
in this order.
Let (the
among
for which
is maximal). We claim that it's enough to check if segment
crosses with segment
, i.e. if it doesn't, then the segment
for any other
also doesn't cross with
.
It's clear that and
cross if and only if point
is below the line
and above the line
. Among the right points that are below
, point
is "furthest around
", so if it's below
, then all other points are too.
So, for each point we need to find its
(it can easily be updated when we calculate
) and check whether segments
and
cross. If there is no such
, then
is a good segment.

The ccw order of points around some center point can be found directly by sorting the points in complexity. It's worth noting that there exists a (much more complicated) algorithm with
complexity that determines this for all points together (so the total complexity of the solution of this task would be
). It uses duality to transform it into the line arrangement problem.
Comments