This page is still under construction.

Parts of this page are still being built. What you see may change.

Cuckoo Hashing

Time limit1sMemory limit128 MB

Summary
Given each word's two hash slots, decide whether inserting all words in order avoids an infinite cuckoo eviction chain.
Level

Medium6 of 10

Topics
Graph, DFS, Math
Solved
No attempts yet

Problem

One of the most fundamental data-structure problems is the dictionary problem: given a set DD of words, you want to quickly decide whether any query string qq belongs to DD. Hashing is a classic solution. You design a fast, deterministic hash function h:Σ∗→[0..n−1]h : \Sigma^* \to [0..n-1] that maps every string into the integer range {0,1,…,n−1}\{0, 1, \dots, n-1\}, allocate an empty table TT of size nn, and for each word w∈Dw \in D set T[h(w)]=wT[h(w)] = w. To answer a query qq you compute h(q)h(q) and check whether T[h(q)]=qT[h(q)] = q.

The catch is collisions: two different words may hash to the same slot (recall the birthday paradox — in a class of 24 pupils there is already more than a 50% chance that two share a birthday). On average you can only store about n\sqrt{n} words before a collision occurs, which wastes a lot of space.

Cuckoo hashing is a stronger variant that uses two hash functions h1h_1 and h2h_2, so each word has two candidate slots. To answer a query qq you compute both h1(q)h_1(q) and h2(q)h_2(q) and report that q∈Dq \in D if T[h1(q)]=qT[h_1(q)] = q or T[h2(q)]=qT[h_2(q)] = q.

The name comes from how the table is built. Start with an empty table and insert the words one by one. To insert a word dd:

  • If T[h1(d)]T[h_1(d)] is free, set T[h1(d)]=dT[h_1(d)] = d.
  • Otherwise, if T[h2(d)]T[h_2(d)] is free, set T[h2(d)]=dT[h_2(d)] = d.
  • Otherwise both slots are occupied. Like a cuckoo pushing other birds' eggs out of the nest, evict the word rr currently in T[h1(d)]T[h_1(d)], set T[h1(d)]=dT[h_1(d)] = d, and reinsert rr into its alternative slot. If that slot is also occupied, evict its word and relocate it in the same way, and so on.

This relocation chain may never terminate. If it loops forever, the table has to be rebuilt with different hash functions. Fortunately, with high probability this does not happen as long as DD contains at most n/2n/2 words.

Given, for every word, the two slots it hashes to, decide whether all words can be inserted in the given order without falling into an infinite relocation loop.

(Cuckoo hashing was proposed by R. Pagh and F. F. Rödler in 2001.)

Input

The first line contains a single integer tt (1≤t≤501 \le t \le 50), the number of test cases.

Each test case starts with a line containing two integers mm and nn (1≤m≤n≤100001 \le m \le n \le 10000), where mm is the number of words in the dictionary and nn is the size of the hash table. Each of the next mm lines describes one word did_i (in insertion order) by two integers h1(di)h_1(d_i) and h2(di)h_2(d_i) (0≤h1(di),h2(di)<n0 \le h_1(d_i), h_2(d_i) < n), its two hash values. The two values may be equal.

Output

For each test case, print a single line: successful hashing if all words can be inserted in the given order, or rehash necessary if it is impossible.

Examples1

  1. Example 1

    Input
    2
    3 3
    0 1
    1 2
    2 0
    5 6
    2 3
    3 1
    1 2
    5 1
    2 5
    
    Expected output
    successful hashing
    rehash necessary