#include <vector>
#include <unordered_map>
#include <fstream>
#include <iostream>
class heap {
std::vector<int> elements;
public:
heap() {
//to be easy to work with it
elements.push_back(-1);
};
void heapify( int n, int i) {
int smallest = i;
int left = 2 * i;
int right = 2 * i + 1;
if (left <= n && elements[left] < elements[smallest])
smallest = left;
if (right <= n && elements[right] < elements[smallest])
smallest = right;
if (smallest != i) {
std::swap(elements[i], elements[smallest]);
heapify( n, smallest);
}
}
void buildHeap() {
int n = elements.size() - 1; // because index 0 is unused
for (int i = n / 2; i >= 1; --i) {
heapify(n, i);
}
}
void Merge(heap &rhs)
{
for (int i=1;i<=rhs.elements.size()-1;i++) {
elements.push_back(rhs.elements[i]);
}
buildHeap();
}
void insert(int val) {
elements.push_back(val);
int index=elements.size()-1;
while (elements[index]<elements[index/2]) {
std::swap(elements[index], elements[index/2]);
index/=2;
}
}
int findMin()
{
if (isEmpty())
throw std::out_of_range("Heap is empty");
return elements[1];
}
void makeEmpty()
{
elements.clear();
elements.push_back(-1);
}
heap(const heap& other)
{
this->elements=other.elements;
}
bool isEmpty()
{
if (elements.size() == 1)
return true;
return false;
}
void deleteMin()
{
if (isEmpty())
throw std::out_of_range("Heap is empty");
std::swap(elements[1], elements[elements.size()-1]);
elements.pop_back();
heapify( elements.size()-1,1);
}
heap &operator =(heap & rhs)= default;
};
std::ifstream f("../mergeheap.in");
std::ofstream g("../mergeheap.out");
int main() {
int n,q;
f>>n>>q;
std::vector<heap> heaps(n+3);
while (q--) {
int c;
f>>c;
if (c==1) {
int m,x;
f>>m>>x;
heaps[m].insert(x);
}else if (c==2) {
int m;
f>>m;
g<<heaps[m].findMin()<<"\n";
heaps[m].deleteMin();
}else {
int a,b;
f>>a>>b;
heaps[a].Merge(heaps[b]);
heaps[b].makeEmpty();
}
}
return 0;
}