def get_i() #空白区切の入力を数値(整数)の配列で返す
  return gets.chomp.split(" ").map(&:to_i)
end
def get_f() #空白区切の入力を数値(実数)の配列で返す
  return gets.chomp.split(" ").map(&:to_f)
end
def get() #空白区切の入力を文字列の配列で返す
  return gets.chomp.split(" ")
end
def get_nsp() #入力されたものを一文字ずつに区切った文字列の配列で返す
  return gets.chomp.split("")
end
def yn_judge(bool,y="Yes",n="No") #boolに真偽を投げることで、trueならy、falseならnの値を出力する
  return bool ? y : n 
end
def array(size,n=1,init=nil) #nに配列の次元数、sizeに配列の大きさ、initに初期値を投げることでその配列を返す
  if n==1
    return Array.new(size){init}
  else
    return Array.new(n).map{Array.new(size){init}}
  end
end

class PQ
  attr_accessor:queue,:n
  def initialize(n)
    @n=0
    @queue=array(n,1,10**9)
  end

  def push_q(x)
    i=@n
    @n+=1
    while i>0
      p=(i-1)/2
      break if @queue[p]>x
      @queue[i]=@queue[p]
      i=p
    end
    @queue[i]=x
  end

  def pop_q()
    min=@queue[0]
    @n-=1 unless @n.zero?
    x=@queue[@n]
    i=0
    while i*2+1<@n
      l=i*2+1
      r=i*2+2
      l=r if r<@n and @queue[l]<@queue[r]
      break if @queue[l]<=x
      @queue[i]=@queue[l]
      i=l
    end
    @queue[i]=x
    return min
  end
end

n,q=get_i
pq=array(n,1)
n.times do|i|
  pq[i]=PQ.new((2*10**5)/n)
end
q.times do
  query=get_i
  case query[0]
  when 0 then
    pq[query[1]].push_q(query[2])
  when 1 then
    puts pq[query[1]].queue[0]  unless pq[query[1]].n.zero?
  when 2 then
    pq[query[1]].pop_q()  
  end
end

