Skip to content

USACO 2024 December Contest Silver Division - 2D Conveyor Belt#

Problem link: here

Video link: here

Solution Author: Stefan Dascalescu

Problem Solution#

This problem can be very tricky if not approached in the right direction, which is why it's very important to be careful with how you start working on it. A very common idea for problems like this is to process the answers backwards and focus on uniting cells rather than destroying connected components.

Therefore, we can start thinking at creating a graph where for a given point, we create edges to the cells it can reach (if the cell has a direction, we only have one edge, otherwise we have four of them) and whenever a cell gets freed, we start a traversal from that cell to see which other cells we will be able to visit as a result of adding that position in the connected structure.

For more implementation details, I recommend reading the code or watching the video above.

Source code#

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

#include <bits/stdc++.h>

using namespace std;

const int MAXN = 1'000;
const int NDIR = 4;
const int DLIN[NDIR] = {-1, 0, 1, 0};
const int DCOL[NDIR] = {0, 1, 0, -1};
const int MAXQ = 200'000;
const int MAXVAL = MAXN * MAXN;
const int CH_DIR[NDIR] = {'U', 'R', 'D', 'L'};

int idx[MAXN + 2][MAXN + 2], lin[MAXQ], col[MAXQ], answer, qanswer[MAXQ];
int viz[MAXVAL + 1], isquery[MAXN + 1][MAXN + 1];
char change[MAXQ];
vector<int> g[MAXVAL + 1];
queue<int> q;

void addEdge(int a, int b) {
    if(viz[b]) {
        if(!viz[a]) {
            q.push(a);
            viz[a] = 1;
            answer--;
            while(!q.empty()) {
                int node = q.front();
                q.pop();
                for(int i = 0; i < (int)g[node].size(); i++) {
                    if(!viz[g[node][i]]) {
                        viz[g[node][i]] = 1;
                        answer--;
                        q.push(g[node][i]);
                    }
                }
                g[node].clear();
            }
        }
    } else {
        g[b].push_back(a);
    }
}

int main() {
    int n, q;
    cin >> n >> q;
    int ptr = 0;
    for(int i = 1; i <= n; i++) {
        for(int j = 1; j <= n; j++) {
            idx[i][j] = ++ptr;
        }
    }

    answer = n * n;
    viz[0] = 1;
    for(int i = 0; i < q; i++) {
        char ch;
        cin >> lin[i] >> col[i] >> ch;
        for(int dir = 0; dir < NDIR; dir++) {
            if(ch == CH_DIR[dir]) {
                change[i] = dir;
            }
        }
        isquery[lin[i]][col[i]] = 1;

        int newlin = lin[i] + DLIN[change[i]], newcol = col[i] + DCOL[change[i]];
        addEdge(idx[lin[i]][col[i]], idx[newlin][newcol]);
    }

    for(int i = 1; i <= n; i++) {
        for(int j = 1; j <= n; j++) {
            if(!isquery[i][j]) {
                for(int dir = 0; dir < NDIR; dir++) {
                    int newlin = i + DLIN[dir], newcol = j + DCOL[dir];
                    addEdge(idx[i][j], idx[newlin][newcol]);
                }
            }
        }
    }

    for(int i = q - 1; i >= 0; i--) {
        qanswer[i] = answer;
        for(int dir = 0; dir < NDIR; dir++) {
            if(change[i] != dir) {
                int newlin = lin[i] + DLIN[dir], newcol = col[i] + DCOL[dir];
                addEdge(idx[lin[i]][col[i]], idx[newlin][newcol]);
            }
        }
    }

    for(int i = 0; i < q; i++) {
        cout << qanswer[i] << "\n";
    }

    return 0;
}