Skip to content

USACO 2024 US Open Contest Silver Division - Painting Fence Posts#

Problem link: here

Solution Author: Stefan Dascalescu

Problem Solution#

We can create a vector that holds each edge between two different fences. We can easily find the edges by noting that on each row/column as there will always be an even number of fences and every two will form an edge.

To find the length of a road, we are interested in the following:

  • the length from a given fence to the respective point
  • the perimeter of the fence
  • a method to quickly find the distance between two fences.

All these subproblems boil down to implementation, the idea of solving being easy.

Source code#

The source code in C++ can be seen below.

#include <bits/stdc++.h>
#define int long long
using namespace std;
const int NMAX=2e5;
int n, p;
pair <int, int> posts[NMAX+5];
map <int, vector <pair <int, int>>> x, y;
vector <vector <int>> adj;
vector <int> len;
vector <int> index_ord;
int mars[NMAX+5];
struct position
{
    int index, l_fence;
    long long val ()
    {
        return len[index]+l_fence;
    }
    int nxt ()
    {
        if (l_fence==0)
            return index;
        return index+1;
    }
    int prev ()
    {
        return index;
    }
};
int dist (pair <int, int> x, pair <int, int> y)
{
    return abs (x.first-y.first)+abs (x.second-y.second);
}
optional<position> caut (vector <pair <int, int>> &v, int y)
{
    int i=lower_bound (v.begin(), v.end(), make_pair (y, 0ll))-v.begin();
    if (i<v.size() && v[i].first==y)
    {
        return position {index_ord[v[i].second], 0};
    }
    if (i&1)
    {
        pair <int, int> a=v[i-1], b=v[i];
        if ((index_ord[a.second]+1)%p!=index_ord[b.second]) swap (a, b);
        return position {index_ord[a.second], abs (a.first-y)};
    }
    return nullopt;
}
position getPoz (pair <int, int> a)
{
    if (x.count(a.first))
    {
        auto ret=caut (x[a.first], a.second);
        if (ret.has_value())
            return ret.value ();
    }
    auto ret=caut (y[a.second], a.first);
    return ret.value ();
}
int32_t main ()
{
    cin >> n >> p;
    for (int i=0;i<p;i++)
        cin >> posts[i].first >> posts[i].second;
    for (int i=0;i<p;i++)
    {
        x[posts[i].first].push_back ({posts[i].second, i});
        y[posts[i].second].push_back ({posts[i].first, i});
    }
    adj.resize (p);
    for (auto &chestie : x)
    {
        sort (chestie.second.begin(), chestie.second.end());
        for (int i=0;i<chestie.second.size();i++)
            adj[chestie.second[i].second].push_back (chestie.second[i^1].second);
    }
    for (auto &chestie : y)
    {
        sort (chestie.second.begin(), chestie.second.end());
        for (int i=0;i<chestie.second.size();i++)
            adj[chestie.second[i].second].push_back (chestie.second[i^1].second);
    }
    vector <int> ord;
    ord.push_back (0);
    while (true)
    {
        for (auto x : adj[ord.back()])
        {
            if (ord.size()>1 && ord[ord.size()-2]==x)
                continue;
            ord.push_back (x);
            break;
        }
        if (ord.back()==0)
            break;
    }
    ord.pop_back ();
    len.push_back (0);
    for (int i=1;i<=p;i++)
    {
        len.push_back (len.back()+dist (posts[ord[i-1]], posts[ord[i%p]]));
    }
    index_ord.resize (p);
    for (int i=0;i<p;i++)
        index_ord[ord[i]]=i;
    while (n--)
    {
        pair <int, int> start, end;
        cin >> start.first >> start.second >> end.first >> end.second;
        auto p1=getPoz (start), p2=getPoz (end);
        if (p1.val()>p2.val())
            swap (p1, p2);
        long long perim=len.back();
        if (2*(p2.val()-p1.val())>perim)
        {
            mars[p2.nxt()]++;
            mars[p]--;
            mars[0]++;
            mars[p1.prev()+1]--;
        }
        else
        {
            mars[p1.nxt()]++;
            mars[p2.prev()+1]--;
        }
    }
    for (int i=1;i<p;i++)
        mars[i]+=mars[i-1];
    for (int i=0;i<p;i++)
        cout << mars[index_ord[i]] << "\n";
    return 0;
}