Official

D - Card Pile Query Editorial by en_translator


If we try to manage which pile each card belongs to, or which card each pile maintains, it is likely to exceed the time limit, because the amount of updates required for each operation is large.

Notice that we are not asked to track the number of cards at any point; we need them only for the finishing moment. Let us refine the way to maintain data so that each operation requires a small amount of updates.

To simplify the situation, assume that pile \(i\) has card \(N+i\) as the bottommost card, that is never moved. (This is not necessary if we pay additional attention to the data to be managed, but helps us to make the implementation concise.)

Then, we can track the following data with little cost:

  • \(up_i\): the card right above card \(i\) (or \(-1\) if it is absent)
  • \(down_i\): the card right below card \(i\) (or \(-1\) if it is absent)

On the \(i\)-th operation, for \(D_i = down_{C_i}\), it suffices to apply the following updates:

  • Set \(down_{C_i}\) to \(P_i\).
  • Set \(up_{P_i}\) to \(C_i\).
  • Set \(up_{D_i}\) to \(-1\).

The final answer can be retrieved by, for each \(i\), traversing from card \(W + i\) toward \(up\).

Sample code

#include <bits/stdc++.h>
using namespace std;

int main() {
	int n, q;
	cin >> n >> q;
	vector<int> up(2 * n, -1), down(2 * n, -1);
	for (int i = 0; i < n; i++) up[n + i] = i, down[i] = n + i;
	while (q--) {
		int c, p;
		cin >> c >> p;
		c--; p--;
		int d = down[c];
		down[c] = p;
		up[p] = c;
		up[d] = -1;
	}
	for (int i = 0; i < n; i++) {
		int x = n + i, ans = 0;
		while (up[x] != -1) {
			x = up[x];
			ans++;
		}
		cout << ans << " \n"[i == n - 1];
	}
}

posted:
last update: