C - Cards Query Problem Editorial by cn449
以下、この解説では \(i\) 番目の形式のクエリをクエリ \(i\) と表記します。
配列 \(box_1, box_2, \ldots, box_N\) および \(card_1, card_2, \ldots, card_{200000}\) を持っておきます。\(box_i\) では箱 \(i\) に入っているカードの多重集合、\(card_i\) では \(i\) が書かれたカードが入っている箱の番号の集合を管理します。
クエリ \(1\) では \(card_i\) に \(j\) を追加し、\(box_j\) に \(i\) を追加します。これは各クエリ \(\mathrm{O} (1)\) で行えます。
クエリ \(2\) では問われている対象(具体的には、\(box_i\))に対し昇順に sort をし出力、クエリ \(3\) ではそれに加えて重複要素の削除を行えばよいです。これは出力する数の個数の合計を \(S\) とするとすべてのクエリで合わせて \(\mathrm{O} (S\log S)\) で行うことができ、\(S \leq 200000\) より十分高速です。
クエリ \(1\) のたびに sort を行うと TLE になることに注意してください(例えば、1 1 1
というクエリがたくさん与えられる状況などを考えてください) 。
実装例
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
const int N = 200010;
const int M = 200010;
vector<vector<int>> box(N, vector<int>());
vector<vector<int>> card(M, vector<int>());
int main() {
int n, q;
cin >> n >> q;
vector<vector<int>> ans;
while (q--) {
int t;
cin >> t;
if (t == 1) {
int i, j;
cin >> i >> j;
card[i].push_back(j);
box[j].push_back(i);
}
else if (t == 2) {
int i;
cin >> i;
sort(box[i].begin(), box[i].end());
for (int j = 0; j < box[i].size(); j++) {
cout << box[i][j] << "\n "[j + 1 != box[i].size()];
}
}
else {
int i;
cin >> i;
sort(card[i].begin(), card[i].end());
card[i].erase(unique(card[i].begin(), card[i].end()), card[i].end());
for (int j = 0; j < card[i].size(); j++) {
cout << card[i][j] << "\n "[j + 1 != card[i].size()];
}
}
}
}
posted:
last update: