#include <bits/stdc++.h>
using namespace std;
using FileName = string;
using ChangeID = string;
using RepoID = int;
struct Commit {
int commitID;
int timestamp;
vector<pair<FileName, ChangeID>> changes;
bool operator<(const Commit& other) const {
if (timestamp == other.timestamp) {
return commitID < other.commitID;
}
return timestamp < other.timestamp;
}
};
ostream& operator<<(ostream& os, const Commit& c) {
return os << c.commitID;
}
// Global structures
unordered_map<ChangeID, RepoID> change_to_repo;
unordered_map<RepoID, unordered_map<FileName, ChangeID>> repo_to_changes;
map<RepoID, set<Commit>> repo_to_commits;
set<RepoID> ambiguous_repos;
vector<Commit> commits;
// -------------------- PARSE --------------------
vector<Commit> retrieveCommits() {
int N;
cin >> N;
cin.ignore();
vector<Commit> result;
for (int i = 0; i < N; i++) {
string line;
getline(cin, line);
if (line.empty()) continue;
stringstream ss(line);
string tmp;
int id, timestamp;
// id X timestamp Y
if (!(ss >> tmp >> id >> tmp >> timestamp)) continue;
vector<pair<FileName, ChangeID>> changes;
string file, change;
while (ss >> file >> change) {
changes.emplace_back(file, change);
}
result.push_back({id, timestamp, changes});
}
return result;
}
// -------------------- ADD COMMIT --------------------
void add_commit(const Commit& commit, RepoID repo) {
auto& repoChanges = repo_to_changes[repo];
for (const auto& p : commit.changes) {
const FileName& fileName = p.first;
const ChangeID& changeId = p.second;
// map change -> repo
change_to_repo[changeId] = repo;
auto it = repoChanges.find(fileName);
if (it != repoChanges.end()) {
// conflict => ambiguous
if (it->second != changeId) {
ambiguous_repos.insert(repo);
}
} else {
repoChanges[fileName] = changeId;
}
}
repo_to_commits[repo].insert(commit);
}
// -------------------- QUERIES --------------------
void answerQueries() {
int Q;
cin >> Q;
while (Q--) {
int start, end;
FileName fileName;
ChangeID changeID;
cin >> start >> end >> fileName >> changeID;
auto itRepo = change_to_repo.find(changeID);
// not found
if (itRepo == change_to_repo.end()) {
cout << "\n";
continue;
}
RepoID repo = itRepo->second;
// ambiguous repo
if (ambiguous_repos.count(repo)) {
cout << "AMBIGUOUS\n";
continue;
}
auto& s = repo_to_commits[repo];
Commit lower{INT_MIN, start, {}};
Commit upper{INT_MAX, end, {}};
auto it1 = s.lower_bound(lower);
auto it2 = s.upper_bound(upper);
bool first = true;
for (auto it = it1; it != it2; ++it) {
if (!first) cout << " ";
cout << it->commitID;
first = false;
}
cout << "\n";
}
}
// -------------------- MAIN --------------------
int main() {
commits = retrieveCommits();
RepoID next_repo_id = 0;
for (const auto& commit : commits) {
RepoID matched_repo = next_repo_id;
// find existing repo via ANY changeID
for (const auto& change : commit.changes) {
auto it = change_to_repo.find(change.second);
if (it != change_to_repo.end()) {
matched_repo = it->second;
break;
}
}
if (matched_repo == next_repo_id) {
next_repo_id++;
}
add_commit(commit, matched_repo);
}
answerQueries();
}