#include<iostream>
#include<string>
#include<algorithm>
#include<vector>
#include<iterator>
using namespace std;
int Hash(const string & s, int mod = 101)
{
if (s.empty())
return 0;
int hash = 0, i = 1;
for_each(begin(s), end(s), [&](const char & c)
{
hash += static_cast<int>(c) * i++;
});
return (19 * hash) % mod;
}
class HashTableOA
{
public:
using HashBody = vector<string>;
HashTableOA() : size_(101), count_(0), body_(size_, "EMPTY") {}
void Insert(const string & str)
{
if (Find(str) != -1)
return;
int id = 0;
for (size_t i = 0; i < 20; ++i)
{
id = (Hash(str, size_) + i * i + 23 * i) % size_;
if (body_[id] == "EMPTY" || body_[id] == "DELETED")
{
body_[id] = str;
++count_;
break;
}
// If element is already in hash table: ignore it
else if (body_[id] == str)
break;
}
// If i > 20 we assume that insertion operation could not be performed
}
int Find(const string & str)
{
if (count_ == 0)
return -1;
int id = 0;
for (size_t i = 0; i < 20; ++i)
{
id = (Hash(str, size_) + i * i + 23 * i) % size_;
if (body_[id] == "EMPTY")
return -1;
else if (body_[id] == str)
return id;
}
}
void Remove(const string & str)
{
int id = Find(str);
if (id == -1)
return;
body_[id] = "DELETED";
--count_;
}
friend ostream & operator<<(ostream & os, const HashTableOA & ht)
{
os << ht.count_ << endl;
for (auto it = begin(ht.body_); it != end(ht.body_); ++it)
if (*it != "EMPTY" && *it != "DELETED")
os << distance(begin(ht.body_), it) << ":" << *it << endl;
return os;
}
private:
size_t size_;
size_t count_;
HashBody body_;
};
int main()
{
size_t task_num; cin >> task_num;
for (size_t i = 0; i < task_num; ++i)
{
size_t op_num; cin >> op_num;
string tmp; getline(cin, tmp);
HashTableOA ht;
for (size_t j = 0; j < op_num; ++j)
{
string line; getline(cin, line);
string str(next(find(begin(line), end(line), ':')), end(line));
if (*begin(line) == 'A')
ht.Insert(str);
else
ht.Remove(str);
}
cout << ht;
}
return 0;
}
I2luY2x1ZGU8aW9zdHJlYW0+CiNpbmNsdWRlPHN0cmluZz4KI2luY2x1ZGU8YWxnb3JpdGhtPgojaW5jbHVkZTx2ZWN0b3I+CiNpbmNsdWRlPGl0ZXJhdG9yPgoKdXNpbmcgbmFtZXNwYWNlIHN0ZDsKCmludCBIYXNoKGNvbnN0IHN0cmluZyAmIHMsIGludCBtb2QgPSAxMDEpCnsKCWlmIChzLmVtcHR5KCkpCgkJcmV0dXJuIDA7CglpbnQgaGFzaCA9IDAsIGkgPSAxOwoJZm9yX2VhY2goYmVnaW4ocyksIGVuZChzKSwgWyZdKGNvbnN0IGNoYXIgJiBjKQoJewoJCWhhc2ggKz0gc3RhdGljX2Nhc3Q8aW50PihjKSAqIGkrKzsKCX0pOwoKCXJldHVybiAoMTkgKiBoYXNoKSAlIG1vZDsKfQoKY2xhc3MgSGFzaFRhYmxlT0EKewpwdWJsaWM6Cgl1c2luZyBIYXNoQm9keSA9IHZlY3RvcjxzdHJpbmc+OwoKCUhhc2hUYWJsZU9BKCkgOiBzaXplXygxMDEpLCBjb3VudF8oMCksIGJvZHlfKHNpemVfLCAiRU1QVFkiKSB7fQoKCXZvaWQgSW5zZXJ0KGNvbnN0IHN0cmluZyAmIHN0cikKCXsKCQlpZiAoRmluZChzdHIpICE9IC0xKQoJCQlyZXR1cm47CgoJCWludCBpZCA9IDA7CgkJZm9yIChzaXplX3QgaSA9IDA7IGkgPCAyMDsgKytpKQoJCXsKCQkJaWQgPSAoSGFzaChzdHIsIHNpemVfKSArIGkgKiBpICsgMjMgKiBpKSAlIHNpemVfOwoJCQlpZiAoYm9keV9baWRdID09ICJFTVBUWSIgfHwgYm9keV9baWRdID09ICJERUxFVEVEIikKCQkJewoJCQkJYm9keV9baWRdID0gc3RyOwoJCQkJKytjb3VudF87CgkJCQlicmVhazsKCQkJfQoJCQkvLyBJZiBlbGVtZW50IGlzIGFscmVhZHkgaW4gaGFzaCB0YWJsZTogaWdub3JlIGl0CgkJCWVsc2UgaWYgKGJvZHlfW2lkXSA9PSBzdHIpCgkJCQlicmVhazsKCQl9CgkJLy8gSWYgaSA+IDIwIHdlIGFzc3VtZSB0aGF0IGluc2VydGlvbiBvcGVyYXRpb24gY291bGQgbm90IGJlIHBlcmZvcm1lZAoJfQoKCWludCBGaW5kKGNvbnN0IHN0cmluZyAmIHN0cikKCXsKCQlpZiAoY291bnRfID09IDApCgkJCXJldHVybiAtMTsKCgkJaW50IGlkID0gMDsKCQlmb3IgKHNpemVfdCBpID0gMDsgaSA8IDIwOyArK2kpCgkJewoJCQlpZCA9IChIYXNoKHN0ciwgc2l6ZV8pICsgaSAqIGkgKyAyMyAqIGkpICUgc2l6ZV87CgkJCWlmIChib2R5X1tpZF0gPT0gIkVNUFRZIikKCQkJCXJldHVybiAtMTsKCQkJZWxzZSBpZiAoYm9keV9baWRdID09IHN0cikKCQkJCXJldHVybiBpZDsKCQl9Cgl9CgoJdm9pZCBSZW1vdmUoY29uc3Qgc3RyaW5nICYgc3RyKQoJewoJCWludCBpZCA9IEZpbmQoc3RyKTsKCQlpZiAoaWQgPT0gLTEpCgkJCXJldHVybjsKCQlib2R5X1tpZF0gPSAiREVMRVRFRCI7CgkJLS1jb3VudF87Cgl9CgoJZnJpZW5kIG9zdHJlYW0gJiBvcGVyYXRvcjw8KG9zdHJlYW0gJiBvcywgY29uc3QgSGFzaFRhYmxlT0EgJiBodCkKCXsKCQlvcyA8PCBodC5jb3VudF8gPDwgZW5kbDsKCQlmb3IgKGF1dG8gaXQgPSBiZWdpbihodC5ib2R5Xyk7IGl0ICE9IGVuZChodC5ib2R5Xyk7ICsraXQpCgkJCWlmICgqaXQgIT0gIkVNUFRZIiAmJiAqaXQgIT0gIkRFTEVURUQiKQoJCQkJb3MgPDwgZGlzdGFuY2UoYmVnaW4oaHQuYm9keV8pLCBpdCkgPDwgIjoiIDw8ICppdCA8PCBlbmRsOwoJCXJldHVybiBvczsKCX0KCnByaXZhdGU6CglzaXplX3Qgc2l6ZV87CglzaXplX3QgY291bnRfOwoJSGFzaEJvZHkgYm9keV87Cn07CgppbnQgbWFpbigpCnsKCXNpemVfdCB0YXNrX251bTsgY2luID4+IHRhc2tfbnVtOwoJZm9yIChzaXplX3QgaSA9IDA7IGkgPCB0YXNrX251bTsgKytpKQoJewoJCXNpemVfdCBvcF9udW07IGNpbiA+PiBvcF9udW07CgkJc3RyaW5nIHRtcDsgZ2V0bGluZShjaW4sIHRtcCk7CgkJSGFzaFRhYmxlT0EgaHQ7CgkJZm9yIChzaXplX3QgaiA9IDA7IGogPCBvcF9udW07ICsraikKCQl7CgkJCXN0cmluZyBsaW5lOyBnZXRsaW5lKGNpbiwgbGluZSk7CgkJCXN0cmluZyBzdHIobmV4dChmaW5kKGJlZ2luKGxpbmUpLCBlbmQobGluZSksICc6JykpLCBlbmQobGluZSkpOwoJCQlpZiAoKmJlZ2luKGxpbmUpID09ICdBJykKCQkJCWh0Lkluc2VydChzdHIpOwoJCQllbHNlCgkJCQlodC5SZW1vdmUoc3RyKTsKCQl9CgkJY291dCA8PCBodDsKCX0KCglyZXR1cm4gMDsKfQ==