Baltic OI 2016 - Park

Author: Michael Cao

Official Analysis

TL;DR

Draw lines between circles and to borders, and use DSU to answer queries offline.

Intuition

In this problem, we're given a park with circles of differing radii and asked whether some circle can move from a corner of the park to another corner. Upon first glance, this task seems quite challenging and probably involves some not-so-fun geometry. However, the final solution turns out to be quite nice, and not too hard to implement either.

Let's call the circle you are moving around between exits xx. We claim that xx can move between two circles aa and bb as long as dist(a,b)arbrxrdist(a, b) - a_r - b_r \leq x_r, where xrx_r denotes the radius of xx, ara_r and brb_r denote the radius of aa and bb and dist(a,b)dist(a, b) denotes the distance between the centers of aa and bb. Also, let's add horizontal and vertical line segments from each border of the park to each circle with the distance between them as well.

Finally, observe that you can go from exit e1e_1 to exit e2e_2 as long as there isn't some chain of line segments with weight xr\leq x_r that completely blocks off the path between exits. For example, you can go from the top-right exit to the bottom-left exit as long as there isn't a chain of line segments from the top border to the bottom, top to right, bottom to left, or left to right.

Creating a Graph

Now, you have some circles with weights between each other. Let's transform each of the line segments we defined before into an edge, and each circle and border into a node, creating n2+4nn ^ 2 + 4n edges overall and n+4n + 4 nodes.

The problem of checking whether we can go between two exits now becomes checking, for some rr, whether edges with weight r\leq r connect certain borders (this involves some casework).

Offline Queries and DSU

To efficently answer queries of whether two borders are connected, let's process them in order of increasing xrx_r and store a DSU. Now, we can add edges one by one as long as their weight xr\leq x_r, and then check connectivity between the border nodes.

Warning!

When computing distance between two circles, make sure to subtract the radius of both. We want the distance between the borders, not the centers.

Implementation

#include <bits/stdc++.h>
using namespace std;
using ll = long long;
using vi = vector<int>;
#define pb push_back
#define rsz resize
#define all(x) begin(x), end(x)
#define sz(x) (int)(x).size()

Join the USACO Forum!

Stuck on a problem, or don't understand a module? Join the USACO Forum and get help from other competitive programmers!