#include <limits>
#include <iterator>
#include <utility>
#include <algorithm>
#include <vector>
#include <string>
#include <iostream>
namespace lc {
template <typename Traits>
class SegmentTree {
public:
	typedef typename Traits::value_type value_type;
private:
	Traits m_traits;
	std::vector<value_type> m_data;
	int m_size;
	void initialize(){
		for(int i = m_size - 2; i >= 0; --i){
			m_data[i] = m_traits(m_data[i * 2 + 1], m_data[i * 2 + 2]);
		}
	}
	value_type query(int a, int b, int k, int l, int r) const {
		if(r <= a || b <= l){ return m_traits.default_value(); }
		if(a <= l && r <= b){ return m_data[k]; }
		const value_type vl = query(a, b, k * 2 + 1, l, (l + r) / 2);
		const value_type vr = query(a, b, k * 2 + 2, (l + r) / 2, r);
		return m_traits(vl, vr);
	}
public:
	template <typename Iterator>
	SegmentTree(
		Iterator first, Iterator last, const Traits &traits = Traits()) :
		m_size(1), m_traits(traits)
	{
		const int n = std::distance(first, last);
		while(m_size < n){ m_size *= 2; }
		m_data.resize(m_size * 2 - 1, m_traits.default_value());
		std::copy(first, last, m_data.begin() + m_size - 1);
		initialize();
	}
	void update(int i, const value_type &val){
		i += m_size - 1;
		m_data[i] = val;
		while(i > 0){
			i = (i - 1) / 2;
			m_data[i] = m_traits(m_data[i * 2 + 1], m_data[i * 2 + 2]);
		}
	}
	value_type query(int a, int b) const {
		return query(a, b, 0, 0, m_size);
	}
};
}
namespace lc {
template <class T>
struct MinTraits {
	typedef T value_type;
	value_type default_value() const {
		return std::numeric_limits<value_type>::max();
	}
	value_type operator()(const value_type &a, const value_type &b) const {
		return std::min(a, b);
	}
};
}
using namespace std;
typedef pair<string, int> psi;
typedef long long ll;
int main(){
	ios_base::sync_with_stdio(false);
	int n;
	cin >> n;
	vector<psi> table(n);
	for(int i = 0; i < n; ++i){
		cin >> table[i].first;
		table[i].second = i;
	}
	sort(table.begin(), table.end());
	vector<int> inv(n);
	for(int i = 0; i < n; ++i){ inv[table[i].second] = i; }
	vector<int> lcp(n);
	for(int i = 0; i + 1 < n; ++i){
		const int len = min(table[i].first.size(), table[i + 1].first.size());
		for(lcp[i] = 0; lcp[i] < len; ++lcp[i]){
			if(table[i].first[lcp[i]] != table[i + 1].first[lcp[i]]){ break; }
		}
	}
	lc::SegmentTree<lc::MinTraits<int>> lcp_st(lcp.begin(), lcp.end());
	vector<int> range_table(n);
	for(int i = 0; i < n; ++i){
		const int len = table[i].first.size();
		int l = i + 1, r = n;
		while(l < r){
			const int c = l + (r - l) / 2;
			if(lcp_st.query(i, c) >= len){
				l = c + 1;
			}else{
				r = c;
			}
		}
		range_table[i] = l;
	}
	const ll llinf = numeric_limits<ll>::max();
	vector<ll> occur_st_init(n, llinf);
	lc::SegmentTree<lc::MinTraits<ll>> occur_st(
		occur_st_init.begin(), occur_st_init.end());
	int q;
	cin >> q;
	while(q--){
		int t, s;
		cin >> t >> s;
		--s;
		if(t == 1){
			occur_st.update(inv[s], (static_cast<ll>(inv[s]) << 32) | s);
		}else if(t == 2){
			occur_st.update(inv[s], llinf);
		}else if(t == 3){
			const ll k = occur_st.query(inv[s], range_table[inv[s]]);
			if(k >= llinf){
				cout << "-1\n";
			}else{
				cout << (k & 0x7fffffff) + 1 << "\n";
			}
		}
	}
	return 0;
}


Measured memory_bytes: 12348