Search for a command to run...
Progressive hints first, then the full explanation and implementation when you're ready to cash out.
Review status
AI-generated and still unreviewed. Double-check the details before internalizing them.
Hints
Open only as much as you need to keep the solve alive.
The three conditions are exactly forbidding an alternating checkerboard. So stop staring at colors; stare at two row sets.
For two rows, let and be their black-column sets. A violation exists iff both and are nonempty.
So the matrix is good iff all row black sets form one inclusion chain. If you sort row sizes, the matching column sizes must be the conjugate Young diagram.
You do not need to know the actual shape after each query. Keep only row counts, column counts, and histograms of heights.
When adding , one actual column height changes . On the expected Young diagram, only threshold changes, where is the old row count; its value is , so one expected height changes .
Research note: I checked the Codeforces statement, the official tutorial page whose G1/F1/F2 section is currently just the placeholder, public accepted-status pages such as F1 status, and a Codeforces comment on that tutorial page pointing at the Young-diagram/count-histogram approach. The proof below is derived from the supplied statement; no source text is copied.
The forbidden configuration is just a checkerboard:
For row , let be the set of columns where row is black. For two rows , a bad checkerboard exists exactly when the two sets are incomparable: there is some column in and some column in . The order of those two columns does not save you; whichever is smaller becomes , the other becomes , and boom, checkerboard. Conversely, any checkerboard gives one column from each difference. Therefore:
This is the first big trap: the row indices do not need to be monotone. We are allowed to conceptually reorder rows and columns. The property is about nested sets, not about row being above row in some nice visual way.
Now sort row counts in nonincreasing order:
If the row sets are nested, these counts describe a Young diagram. Its column heights are the conjugate partition:
So the actual multiset of column black counts must equal the multiset , including zeroes. That last bit matters; ignoring empty columns is how bugs sneak in wearing a fake mustache.
The converse is also true. Suppose the actual column-count multiset equals the conjugate of the sorted row-count multiset. Let be the number of nonempty rows. Since no empty row contains black cells, any column with height must be black in every nonempty row. Such a column exists by the multiset equality. Remove it and subtract from every nonempty row count. The remaining expected column-height multiset is just the old conjugate with removed. Repeat. Each removed column is present in exactly the rows that are still active, so the rows are forced into nested sets. Thus the count criterion is equivalent to monotonicity.
So we maintain this criterion dynamically.
Let be the number of actual columns with exactly black cells.
Let be the number of rows with at least black cells:
The expected conjugate-column multiset contains one value for every . Define
The matrix is monotone iff
Maintain and a counter bad = number of with . Answer is YES iff bad == 0.
Initially all cells are white. Then , and since for all , also . All differences are zero.
For a query adding cell :
Then the expected histogram changes as and .
Since , these four histogram moves become four point updates to :
We get using a Fenwick tree over row-count frequencies. The Fenwick tree supports updating one row count and querying how many rows have count at least some threshold.
Complexity per query is , with memory. Across all test cases this is easily fine for and .
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
void setIO() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
}
struct Fenwick {
int n;
vector<int> bit;
Fenwick(int n = 0) { init(n); }
void init(int n_) {
n = n_;
bit.assign(n + 1, 0);
}
void add(int idx, int val) {
for (; idx <= n; idx += idx & -idx) bit[idx] += val;
}
int sum(int idx) const {
int res = 0;
for (; idx > 0; idx -= idx & -idx) res += bit[idx];
return res;
}
};
int main() {
setIO();
int T;
cin >> T;
while (T--) {
int n, q;
cin >> n >> q;
vector<int> row(n + 1, 0), col(n + 1, 0), diff(n + 1, 0);
Fenwick fw(n + 1);
fw.add(1, n);
int bad = 0;
auto touch = [&](int h, int delta) {
int before = diff[h];
int after = before + delta;
if (before == 0 && after != 0) ++bad;
if (before != 0 && after == 0) --bad;
diff[h] = after;
};
while (q--) {
int r, c;
cin >> r >> c;
int a = row[r];
int b = col[c];
int x = n - fw.sum(a + 1);
touch(b, -1);
touch(b + 1, 1);
touch(x, 1);
touch(x + 1, -1);
fw.add(a + 1, -1);
fw.add(a + 2, 1);
++row[r];
++col[c];
cout << (bad == 0 ? "YES\n" : "NO\n");
}
}
}#include <bits/stdc++.h>
using namespace std;
using ll = long long;
void setIO() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
}
struct Fenwick {
int n;
vector<int> bit;
Fenwick(int n = 0) { init(n); }
void init(int n_) {
n = n_;
bit.assign(n + 1, 0);
}
void add(int idx, int val) {
for (; idx <= n; idx += idx & -idx) bit[idx] += val;
}
int sum(int idx) const {
int res = 0;
for (; idx > 0; idx -= idx & -idx) res += bit[idx];
return res;
}
};
int main() {
setIO();
int T;
cin >> T;
while (T--) {
int n, q;
cin >> n >> q;
vector<int> row(n + 1, 0), col(n + 1, 0), diff(n + 1, 0);
Fenwick fw(n + 1);
fw.add(1, n);
int bad = 0;
auto touch = [&](int h, int delta) {
int before = diff[h];
int after = before + delta;
if (before == 0 && after != 0) ++bad;
if (before != 0 && after == 0) --bad;
diff[h] = after;
};
while (q--) {
int r, c;
cin >> r >> c;
int a = row[r];
int b = col[c];
int x = n - fw.sum(a + 1);
touch(b, -1);
touch(b + 1, 1);
touch(x, 1);
touch(x + 1, -1);
fw.add(a + 1, -1);
fw.add(a + 2, 1);
++row[r];
++col[c];
cout << (bad == 0 ? "YES\n" : "NO\n");
}
}
}