Problem:
Multi-Map

For a dictionary $M$ that stores elements formed by a pair of a string key and an integer value, perform a sequence of the following operations. Note that multiple elements can have equivalent keys.

insert($key$, $x$): Insert an element formed by a pair of $key$ and $x$ to $M$.

get($key$): Print all values with the specified $key$.

delete($key$): Delete all elements with the specified $key$.

dump($L$, $R$): Print all elements formed by a pair of the key and the value such that the key is greater than or equal to $L$ and less than or equal to $R$ in lexicographic order.

Input

The input is given in the following format.

$q$
$query_1$
$query_2$
:
$query_q$

Each query $query_i$ is given by

0 $key$ $x$

or

1 $key$

or

2 $key$

or

3 $L$ $R$

where the first digits 0, 1, 2 and 3 represent insert, get, delete and dump operations.

Output

For each get operation, print the corresponding values in the order of insertions.

For each dump operation, print the corresponding elements formed by a pair of the key and the value. For the dump operation, print the elements in ascending order of the keys, in case of a tie, in the order of insertions.

Constraints

$1 \leq q \leq 200,000$

$1 \leq x \leq 1,000,000,000$

$1 \leq $ length of $key$ $ \leq 20$

$key$ consists of lower-case letters

$L \leq R$ in lexicographic order

The total number of elements printed by get operations does not exceed $500,000$

The total number of elements printed by dump operations does not exceed $500,000$

Sample Input 1

10
0 blue 6
0 red 1
0 blue 4
0 white 5
1 red
1 blue
2 red
1 black
1 red
3 w z

Sample Output 1

1
6
4
white 5

Solution in Go (judge verdict: Accepted)

package main

import (
	"bufio"
	"fmt"
	"os"
	"sort"
	"strconv"
	"strings"
)

func configure(scanner *bufio.Scanner) {
	scanner.Split(bufio.ScanWords)
	scanner.Buffer(make([]byte, 1000005), 1000005)
}
func getNextString(scanner *bufio.Scanner) string {
	scanned := scanner.Scan()
	if !scanned {
		panic("scan failed")
	}
	return scanner.Text()
}
func getNextInt(scanner *bufio.Scanner) int {
	i, _ := strconv.Atoi(getNextString(scanner))
	return i
}
func getNextInt64(scanner *bufio.Scanner) int64 {
	i, _ := strconv.ParseInt(getNextString(scanner), 10, 64)
	return i
}
func getNextFloat64(scanner *bufio.Scanner) float64 {
	i, _ := strconv.ParseFloat(getNextString(scanner), 64)
	return i
}
func main() {
	fp := os.Stdin
	wfp := os.Stdout
	extra := 0
	if os.Getenv("I") == "IronMan" {
		fp, _ = os.Open(os.Getenv("END_GAME"))
		extra = 100
	}
	scanner := bufio.NewScanner(fp)
	configure(scanner)
	writer := bufio.NewWriter(wfp)
	defer func() {
		r := recover()
		if r != nil {
			fmt.Fprintln(writer, r)
		}
		writer.Flush()
	}()
	solve(scanner, writer)
	for i := 0; i < extra; i++ {
		fmt.Fprintln(writer, "-----------------------------------")
		solve(scanner, writer)
	}
}
func solve(scanner *bufio.Scanner, writer *bufio.Writer) {
	q := getNextInt(scanner)
	m := map[string][]int{}
	qq := make([]query, q)
	ss := make([]string, 0)
	for i := 0; i < q; i++ {
		qq[i].t = getNextInt(scanner)
		switch qq[i].t {
		case 0:
			qq[i].key = getNextString(scanner)
			ss = append(ss, qq[i].key)
			qq[i].x = getNextInt(scanner)
		case 1:
			qq[i].key = getNextString(scanner)
			ss = append(ss, qq[i].key)
		case 2:
			qq[i].key = getNextString(scanner)
			ss = append(ss, qq[i].key)
		case 3:
			qq[i].l = getNextString(scanner)
			qq[i].r = getNextString(scanner)
			ss = append(ss, qq[i].l)
			ss = append(ss, qq[i].r)
		}
	}
	c := newCompress(ss)
	r := map[int]string{}
	for v, i := range c {
		r[i] = v
	}
	seg := newSegment(len(c) + 1)
	for i := 0; i < q; i++ {
		switch qq[i].t {
		case 0:
			m[qq[i].key] = append(m[qq[i].key], qq[i].x)
			seg.update(c.get(qq[i].key), 1, seg.add)
		case 1:
			for k := 0; k < len(m[qq[i].key]); k++ {
				fmt.Fprintln(writer, m[qq[i].key][k])
			}
		case 2:
			delete(m, qq[i].key)
			seg.update(c.get(qq[i].key), 0, seg.add)
		case 3:
			for j := seg.right(0, c.get(qq[i].l), 1); j <= c.get(qq[i].r); j = seg.right(0, j+1, 1) {
				for k := 0; k < len(m[r[j]]); k++ {
					fmt.Fprintln(writer, fmt.Sprintf("%s %d", r[j], m[r[j]][k]))
				}
			}
		}
	}
}

type query struct {
	t, x int
	key  string
	l, r string
}
type segment [][]int

func newSegment(n int) segment {
	seg := make(segment, 0)
	for n > 1 {
		seg = append(seg, make([]int, n))
		n = (n + 1) >> 1
	}
	seg = append(seg, make([]int, 1))
	return seg
}
func (seg segment) update(i int, v int, f func(x, y int) int) {
	seg[0][i] = v
	for h := 1; h < len(seg); h++ {
		i >>= 1
		if i<<1+1 < len(seg[h-1]) {
			seg[h][i] = f(seg[h-1][i<<1], seg[h-1][i<<1+1])
		} else {
			seg[h][i] = seg[h-1][i<<1]
		}
	}
}
func (seg segment) add(x, y int) int {
	return x + y
}

func (seg segment) left(h, i, k int) int {
	if i < 0 {
		return -1
	}
	if seg[h][i] < k {
		k -= seg[h][i]
		i--
		if i&1 == 0 {
			return seg.left(h, i, k)
		}
		return seg.left(h+1, i>>1, k)
	}
	if h == 0 {
		return i
	}
	if k <= seg[h][i]-seg[h-1][i<<1] {
		return seg.left(h-1, i<<1+1, k)
	}
	return seg.left(h-1, i<<1, k-seg[h][i]+seg[h-1][i<<1])
}
func (seg segment) right(h, i, k int) int {
	if h >= len(seg) || i >= len(seg[h]) {
		return len(seg[0])
	}
	if seg[h][i] < k {
		k -= seg[h][i]
		i++
		if i&1 == 1 {
			return seg.right(h, i, k)
		}
		return seg.right(h+1, i>>1, k)
	}
	if h == 0 {
		return i
	}
	if k <= seg[h-1][i<<1] {
		return seg.right(h-1, i<<1, k)
	}
	return seg.right(h-1, i<<1+1, k-seg[h-1][i<<1])
}

type compress map[string]int

func newCompress(aa []string) compress {
	n := len(aa)
	bb := make([]string, n)
	copy(bb, aa)
	sort.SliceStable(bb, func(i, j int) bool {
		return strings.Compare(bb[i], bb[j]) == -1
	})
	c := compress{}
	l := 0
	i := 0
	for r := 0; r < n; r++ {
		for r > l && strings.Compare(bb[r], bb[l]) != 0 {
			l++
		}
		if r == l {
			c[bb[l]] = i
			i++
		}
	}
	return c
}
func (c compress) get(x string) int {
	return c[x]
}