#include <bits/stdc++.h>
using namespace std;
// ---------- Core solution ----------
struct FastHashLL {
size_t operator()(long long x) const noexcept {
x += 0x9e3779b97f4a7c15LL;
x = (x ^ (x >> 30)) * 0xbf58476d1ce4e5b9LL;
x = (x ^ (x >> 27)) * 0x94d049bb133111ebLL;
x = x ^ (x >> 31);
return (size_t)x;
}
};
struct DSU {
vector<int> parent, sz;
vector<long long> mn, mx;
vector<char> printed;
int make_node(long long idx) {
int id = (int)parent.size();
parent.push_back(id);
sz.push_back(1);
mn.push_back(idx);
mx.push_back(idx);
printed.push_back(0);
return id;
}
int find(int x) {
while (parent[x] != x) {
parent[x] = parent[parent[x]];
x = parent[x];
}
return x;
}
int unite(int a, int b) {
a = find(a); b = find(b);
if (a == b) return a;
if (sz[a] < sz[b]) swap(a, b);
parent[b] = a;
sz[a] += sz[b];
mn[a] = min(mn[a], mn[b]);
mx[a] = max(mx[a], mx[b]);
printed[a] = printed[a] || printed[b];
return a;
}
};
vector<string> solve(int N, vector<vector<string>> Messages) {
vector<string> out;
out.reserve(N);
DSU dsu;
unordered_map<long long, int, FastHashLL> letterId; letterId.reserve(N*2);
unordered_map<long long, char, FastHashLL> letterAt; letterAt.reserve(N*2);
unordered_set<long long, FastHashLL> starAt; starAt.reserve(N*2);
auto emit_if_ready = [&](int root) {
root = dsu.find(root);
if (dsu.printed[root]) return;
long long L = dsu.mn[root], R = dsu.mx[root];
if (dsu.sz[root] != (int)(R - L + 1)) return; // not contiguous
if (!starAt.count(L - 1) || !starAt.count(R + 1)) return; // not enclosed
string s; s.reserve(dsu.sz[root]);
for (long long i = L; i <= R; ++i) s.push_back(letterAt[i]);
dsu.printed[root] = 1;
out.push_back(move(s));
};
for (int i = 0; i < N; ++i) {
long long idx = stoll(Messages[i][0]);
char ch = Messages[i][1][0];
if (ch == '*') {
starAt.insert(idx);
vector<pair<long long,string>> newly;
auto try_side = [&](long long neighbor, bool starIsLeftBoundary) {
auto it = letterId.find(neighbor);
if (it == letterId.end()) return;
int root = dsu.find(it->second);
long long L = dsu.mn[root], R = dsu.mx[root];
// star must touch the boundary of the block
if (starIsLeftBoundary && L != neighbor) return;
if (!starIsLeftBoundary && R != neighbor) return;
if (dsu.printed[root]) return;
if (dsu.sz[root] != (int)(R - L + 1)) return; // gaps exist
bool enclosed = starIsLeftBoundary ? starAt.count(R + 1)
: starAt.count(L - 1);
if (!enclosed) return;
string s; s.reserve(dsu.sz[root]);
for (long long x = L; x <= R; ++x) s.push_back(letterAt[x]);
dsu.printed[root] = 1;
newly.push_back({L, move(s)});
};
// a new star can close up to two messages (one on each side)
try_side(idx + 1, true);
try_side(idx - 1, false);
if (!newly.empty()) {
sort(newly.begin(), newly.end(),
[](const auto& a, const auto& b){ return a.first < b.first; });
for (auto& p : newly) out.push_back(move(p.second));
}
} else {
if (letterAt.find(idx) != letterAt.end()) continue; // safety
letterAt[idx] = ch;
int id = dsu.make_node(idx);
letterId[idx] = id;
auto itL = letterId.find(idx - 1);
if (itL != letterId.end()) id = dsu.unite(id, itL->second);
auto itR = letterId.find(idx + 1);
if (itR != letterId.end()) id = dsu.unite(id, itR->second);
emit_if_ready(id); // may complete an enclosed block
}
}
return out;
}
// ---------- Driver ----------
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
int N;
if (!(cin >> N)) return 0;
vector<vector<string>> Messages;
Messages.reserve(N);
for (int i = 0; i < N; ++i) {
string idx, ch;
cin >> idx >> ch; // index_number and character as strings
Messages.push_back({idx, ch});
}
vector<string> ans = solve(N, Messages);
for (const string& s : ans) cout << s << '\n';
return 0;
}