#![allow(dead_code, unused_imports)]

use std::fmt::Debug;
use std::str::FromStr;

fn read_stdin() -> String {
    let mut s = String::new();
    std::io::stdin()
        .read_line(&mut s)
        .expect("cannot read stdin");
    s.trim().to_string()
}

fn read<T>() -> T
where
    T: FromStr,
    <T as FromStr>::Err: Debug,
{
    read_stdin().parse::<T>().unwrap()
}

fn read_usize() -> usize {
    read::<usize>()
}

fn read_2<A, B>() -> (A, B)
where
    A: FromStr,
    <A as FromStr>::Err: Debug,
    B: FromStr,
    <B as FromStr>::Err: Debug,
{
    let s = read_stdin();
    let mut s = s.split_whitespace();
    let a = s.next().unwrap().parse::<A>().unwrap();
    let b = s.next().unwrap().parse::<B>().unwrap();
    (a, b)
}

fn read_3<A, B, C>() -> (A, B, C)
where
    A: FromStr,
    <A as FromStr>::Err: Debug,
    B: FromStr,
    <B as FromStr>::Err: Debug,
    C: FromStr,
    <C as FromStr>::Err: Debug,
{
    let s = read_stdin();
    let mut s = s.split_whitespace();
    let a = s.next().unwrap().parse::<A>().unwrap();
    let b = s.next().unwrap().parse::<B>().unwrap();
    let c = s.next().unwrap().parse::<C>().unwrap();
    (a, b, c)
}

fn read_4<A, B, C, D>() -> (A, B, C, D)
where
    A: FromStr,
    <A as FromStr>::Err: Debug,
    B: FromStr,
    <B as FromStr>::Err: Debug,
    C: FromStr,
    <C as FromStr>::Err: Debug,
    D: FromStr,
    <D as FromStr>::Err: Debug,
{
    let s = read_stdin();
    let mut s = s.split_whitespace();
    let a = s.next().unwrap().parse::<A>().unwrap();
    let b = s.next().unwrap().parse::<B>().unwrap();
    let c = s.next().unwrap().parse::<C>().unwrap();
    let d = s.next().unwrap().parse::<D>().unwrap();
    (a, b, c, d)
}

fn read_multiple<T: FromStr>() -> Vec<T>
where
    <T as FromStr>::Err: Debug,
{
    read_stdin()
        .split_whitespace()
        .map(|x| x.parse::<T>().expect("cannot parse stdin"))
        .collect()
}

/// NOTE: sort iter beforehand if required
fn count<T>(iter: &mut impl Iterator<Item = T>) -> Vec<(T, usize)>
where
    T: std::cmp::Ord,
{
    let iter = iter.collect::<Vec<_>>();
    //iter.sort();
    let (mut v, o, c) =
        iter.into_iter()
            .fold((Vec::new(), None, 0), |(mut v, last, count), item| {
                if let Some(o) = last {
                    if item == o {
                        (v, Some(o), count + 1)
                    } else {
                        v.push((o, count));
                        (v, Some(item), 1)
                    }
                } else {
                    (v, Some(item), 1)
                }
            });
    if let Some(i) = o {
        v.push((i, c));
    }
    v
}

fn max_subarray(v: impl Iterator<Item = i64>) -> (i64, (usize, usize)) {
    //assert!(v.len() > 0);
    let mut best_sum = 0;
    let (mut best_start, mut best_end) = (0, 0);
    let mut current_sum = 0;
    let mut current_start = 0;
    for (end, val) in v.enumerate() {
        if current_sum <= 0 {
            current_start = end;
            current_sum = val;
        } else {
            current_sum += val;
        }
        if current_sum > best_sum {
            best_sum = current_sum;
            best_start = current_start;
            best_end = end + 1;
        }
    }
    (best_sum, (best_start, best_end))
}

fn gcd(mut a: u64, mut b: u64) -> u64 {
    while a != 0 {
        let old_m = a;
        a = b % a;
        b = old_m;
    }
    b
}

/// returns gcd, and pair (x, y), such that x * a + b * y == gcd
fn egcd(a: i64, b: i64) -> (i64, i64, i64) {
    if a == 0 {
        (b, 0, 1)
    } else {
        let (g, x, y) = egcd(b % a, a);
        (g, y - (b / a) * x, x)
    }
}

fn factorize(mut n: u64) -> Vec<u64> {
    if n <= 3 {
        return vec![n];
    }
    let mut v = Vec::new();
    while n % 2 == 0 {
        n /= 2;
        v.push(2);
    }
    while n % 3 == 0 {
        n /= 3;
        v.push(3);
    }
    let mut f = 6;
    while (f - 1) * (f - 1) <= n {
        while n % (f - 1) == 0 {
            n /= f - 1;
            v.push(f - 1);
        }
        while n % (f + 1) == 0 {
            n /= f + 1;
            v.push(f + 1);
        }
        f += 6;
    }
    if n > 1 {
        v.push(n);
    }
    v
}

fn compact_factors(n: u64) -> Vec<(u64, usize)> {
    count(&mut factorize(n).into_iter())
}

fn all_factors(n: u64) -> Vec<u64> {
    if n == 0 {
        return vec![0];
    } else if n == 1 {
        return vec![1];
    }
    let factors = compact_factors(n);
    let mut v = vec![1];
    for (fac, num) in factors {
        let ori = v.clone();
        for i in 1..num + 1 {
            v.append(
                &mut ori
                    .clone()
                    .into_iter()
                    .map(|f| f * fac.pow(i as u32))
                    .collect::<Vec<_>>(),
            )
        }
    }
    v.sort();
    v
}

fn abs_diff<T>(a: T, b: T) -> T
where
    T: PartialOrd + std::ops::Sub<Output = T>,
{
    if a > b {
        a - b
    } else {
        b - a
    }
}

struct Permutations<T> {
    inner: Vec<T>,
    state: Vec<usize>,
    i: usize,
    start: bool,
}

impl<T> Permutations<T> {
    fn new(inner: Vec<T>) -> Self {
        Self {
            state: vec![0; inner.len()],
            i: 0,
            start: true,
            inner,
        }
    }
}

/*impl<T, X> From<X> for Permutations<T>
where
    X: IntoIterator<Item = T>,
{
    fn from(f: X) -> Self {
        Self::new(f.into_iter().collect::<Vec<T>>())
    }
}*/

impl<T> Iterator for Permutations<T>
where
    T: Clone,
{
    type Item = Vec<T>;
    fn next(&mut self) -> Option<Self::Item> {
        if self.start {
            self.start = false;
            return Some(self.inner.clone());
        }
        while self.i < self.inner.len() {
            if self.state[self.i] < self.i {
                if self.i % 2 == 0 {
                    self.inner.swap(0, self.i)
                } else {
                    self.inner.swap(self.state[self.i], self.i)
                }
                self.state[self.i] += 1;
                self.i = 0;
                return Some(self.inner.clone());
            } else {
                self.state[self.i] = 0;
                self.i += 1;
            }
        }
        None
    }
}

use std::cmp::{max, min, Ord, Ordering};
use std::collections::{BinaryHeap, VecDeque};
use std::mem::swap;

fn main() -> Result<(), Box<dyn std::error::Error>> {
    for _ in 0..read_usize() {
        let n = read_usize();
        let vec = read_multiple::<u32>();
        let fst = vec[0];
        if vec.iter().all(|x| *x == fst) {
            println!("NO")
        } else {
            println!("YES");
            let (scd_pos, _scd) = vec
                .iter()
                .enumerate()
                .filter(|(_i, v)| **v != fst)
                .next()
                .unwrap();
            println!("{} {}", 1, scd_pos + 1);
            for i in (1..n).filter(|x| *x != scd_pos) {
                if vec[i] == fst {
                    println!("{} {}", i + 1, scd_pos + 1)
                } else {
                    println!("{} {}", i + 1, 1)
                }
            }
        }
    }
    Ok(())
}


// -*- coding:utf-8-unix -*-

#![allow(dead_code)]
#![allow(unused_imports)]

use std::cmp::*;
use std::collections::*;
use std::fs::File;
use std::io::prelude::*;
use std::io::*;
use std::mem;
use std::str;
use std::vec;

const INF: i64 = 1223372036854775807;
const MEM_SIZE: usize = 202020;
const MOD: i64 = 1000000007;
// const MOD: i64 = 998244353;

use std::cmp::*;
use std::collections::*;
use std::io::stdin;
use std::io::stdout;
use std::io::Write;
#[allow(dead_code)]
fn read<T: std::str::FromStr>() -> T {
    let mut s = String::new();
    std::io::stdin().read_line(&mut s).ok();
    s.trim().parse().ok().unwrap()
}

#[allow(dead_code)]
fn readi() -> (i64) {
    let mut str = String::new();
    let _ = stdin().read_line(&mut str).unwrap();
    let mut iter = str.split_whitespace();
    iter.next().unwrap().parse::<i64>().unwrap()
}

#[allow(dead_code)]
fn read_vec<T: std::str::FromStr>() -> Vec<T> {
    read::<String>()
        .split_whitespace()
        .map(|e| e.parse().ok().unwrap())
        .collect()
}
#[allow(dead_code)]
fn read_vec2<T: std::str::FromStr>(n: u32) -> Vec<Vec<T>> {
    (0..n).map(|_| read_vec()).collect()
}

#[allow(dead_code)]
fn readii() -> (i64, i64) {
    let mut str = String::new();
    let _ = stdin().read_line(&mut str).unwrap();
    let mut iter = str.split_whitespace();
    (
        iter.next().unwrap().parse::<i64>().unwrap(),
        iter.next().unwrap().parse::<i64>().unwrap(),
    )
}

#[allow(dead_code)]
fn readiii() -> (i64, i64, i64) {
    let mut str = String::new();
    let _ = stdin().read_line(&mut str).unwrap();
    let mut iter = str.split_whitespace();
    (
        iter.next().unwrap().parse::<i64>().unwrap(),
        iter.next().unwrap().parse::<i64>().unwrap(),
        iter.next().unwrap().parse::<i64>().unwrap(),
    )
}
#[allow(dead_code)]
fn readuu() -> (usize, usize) {
    let mut str = String::new();
    let _ = stdin().read_line(&mut str).unwrap();
    let mut iter = str.split_whitespace();
    (
        iter.next().unwrap().parse::<usize>().unwrap(),
        iter.next().unwrap().parse::<usize>().unwrap(),
    )
}

fn readcc() -> (char, char) {
    let mut str = String::new();
    let _ = stdin().read_line(&mut str).unwrap();
    let mut iter = str.split_whitespace();
    (
        iter.next().unwrap().parse::<char>().unwrap(),
        iter.next().unwrap().parse::<char>().unwrap(),
    )
}

#[allow(dead_code)]
fn readuuu() -> (usize, usize, usize) {
    let mut str = String::new();
    let _ = stdin().read_line(&mut str).unwrap();
    let mut iter = str.split_whitespace();
    (
        iter.next().unwrap().parse::<usize>().unwrap(),
        iter.next().unwrap().parse::<usize>().unwrap(),
        iter.next().unwrap().parse::<usize>().unwrap(),
    )
}

#[allow(dead_code)]
fn readuuuu() -> (usize, usize, usize, usize) {
    let mut str = String::new();
    let _ = stdin().read_line(&mut str).unwrap();
    let mut iter = str.split_whitespace();
    (
        iter.next().unwrap().parse::<usize>().unwrap(),
        iter.next().unwrap().parse::<usize>().unwrap(),
        iter.next().unwrap().parse::<usize>().unwrap(),
        iter.next().unwrap().parse::<usize>().unwrap(),
    )
}

fn solve_part() {
    let n: usize = read();
    let vec: Vec<usize> = read_vec();
    let x = vec[0];
    let mut g1 = vec![0; 0];
    let mut g2 = vec![0; 0];
    for i in 0..n {
        if vec[i] == x {
            g1.push(i);
        } else {
            g2.push(i);
        }
    }
    if g2.is_empty() {
        println!("NO");
        return;
    }
    let y = g2[0];
    println!("YES");
    println!("{:?} {:?}", g1[0] + 1, g2[0] + 1);
    for i in 1..g1.len() {
        println!("{:?} {:?}", g1[i] + 1, g2[0] + 1);
    }
    for i in 1..g2.len() {
        println!("{:?} {:?}", g1[0] + 1, g2[i] + 1);
    }
    return;
}
fn solve() {
    let n: usize = read();
    for i in 0..n {
        solve_part();
    }
    return;
}

fn main() {
    solve()
}


#![allow(unused_imports)]
use {std::cmp::*, std::collections::*, std::io::Write, std::ops::*};

#[allow(unused_macros)]
macro_rules !dbg {($($e :expr ) ,*) =>{#[cfg (debug_assertions ) ] $({let (e ,mut err ) =(stringify !($e ) ,std ::io ::stderr () ) ;writeln !(err ,"{} = {:?}" ,e ,$e ) .unwrap () } ) *} ;}
#[allow(unused_macros)]
macro_rules !min {($a :expr $(,) *) =>{{$a } } ;($a :expr ,$b :expr $(,) *) =>{{std ::cmp ::min ($a ,$b ) } } ;($a :expr ,$($rest :expr ) ,+$(,) *) =>{{std ::cmp ::min ($a ,min !($($rest ) ,+) ) } } ;}
#[allow(unused_macros)]
macro_rules !chmin {($base :expr ,$($cmps :expr ) ,+$(,) *) =>{{let cmp_min =min !($($cmps ) ,+) ;if $base >cmp_min {$base =cmp_min ;true } else {false } } } ;}
#[allow(unused_macros)]
macro_rules !max {($a :expr $(,) *) =>{{$a } } ;($a :expr ,$b :expr $(,) *) =>{{std ::cmp ::max ($a ,$b ) } } ;($a :expr ,$($rest :expr ) ,+$(,) *) =>{{std ::cmp ::max ($a ,max !($($rest ) ,+) ) } } ;}
#[allow(unused_macros)]
macro_rules !chmax {($base :expr ,$($cmps :expr ) ,+$(,) *) =>{{let cmp_max =max !($($cmps ) ,+) ;if $base <cmp_max {$base =cmp_max ;true } else {false } } } ;}

#[allow(dead_code)]
mod scanner {
    use std;
    use std::io::Read;
    use std::str::FromStr;
    use std::str::SplitWhitespace;
    pub struct Scanner<'a> {
        it: SplitWhitespace<'a>,
    }
    impl<'a> Scanner<'a> {
        pub fn new(s: &'a String) -> Scanner<'a> {
            Scanner {
                it: s.split_whitespace(),
            }
        }
        pub fn next<T: FromStr>(&mut self) -> T {
            match self.it.next().unwrap().parse::<T>() {
                Ok(v) => v,
                _ => panic!("Scanner error"),
            }
        }
        pub fn next_chars(&mut self) -> Vec<char> {
            self.next::<String>().chars().collect()
        }
        pub fn next_vec<T: FromStr>(&mut self, len: usize) -> Vec<T> {
            (0..len).map(|_| self.next()).collect()
        }
    }
    pub fn read_string() -> String {
        let mut s = String::new();
        std::io::stdin().read_to_string(&mut s).unwrap();
        s
    }
}

fn main() {
    let sc = scanner::read_string();
    let mut sc = scanner::Scanner::new(&sc);
    let out = std::io::stdout();
    let mut out = std::io::BufWriter::new(out.lock());

    let t: usize = sc.next();
    for _ in 0..t {
        let n: usize = sc.next();
        let a: Vec<usize> = sc.next_vec(n);
        let mut map = std::collections::BTreeMap::<usize, usize>::new();
        let mut idx = 0;
        for &a in a.iter() {
            if !map.contains_key(&a) {
                map.insert(a, idx);
                idx += 1;
            }
        }
        if idx == 1 {
            writeln!(out, "NO").unwrap();
            continue;
        }
        writeln!(out, "YES").unwrap();
        let mut g = vec![vec![]; idx];
        for (i, &a) in a.iter().enumerate() {
            let &j = map.get(&a).unwrap();
            g[j].push(i + 1)
        }
        for i in 1..idx {
            for j in g[i].iter() {
                writeln!(out, "{} {}", g[0][0], j).unwrap();
            }
        }
        for &i in g[0].iter().skip(1) {
            writeln!(out, "{} {}", i, g[1][0]).unwrap();
        }
    }
}


// Template: https://gist.github.com/zheland/a8dd9a39f38f282b98a46e2f4d132697

mod task {
    use crate::input::Input;
    #[allow(unused_imports)]
    use crate::util::*;
    use crate::Mode;
    use std::io::{BufRead, Write};

    pub const MODE: Mode = Mode::Multiple;

    pub fn solution<R, W>(input: &mut Input<R>, output: &mut W)
    where
        R: BufRead,
        W: Write,
    {
        #[allow(unused_imports)]
        use crate::lib::*;
        #[allow(unused_imports)]
        use std::cmp::{max, min};
        #[allow(unused_imports)]
        use std::collections;

        // const N_MAX: usize = 100;
        // let mut a = [0; N_MAX];
        // let sum: i64 = (0..n).map(|_| -> i64 input.next()).sum();
        // let a: Vec<i64> = (0..n).map(|_| -> i64 input.next()).collect();

        let n: usize = input.next();
        let mut b1 = None;
        let mut b2 = None;
        let mut b2j = None;
        for j in 1..=n {
            let b: i32 = input.next();
            if b1 == None {
                b1 = Some(b);
            } else if Some(b) == b1 {
                if let Some(b2j) = b2j {
                    writeln!(output, "{} {}", b2j, j).unwrap();
                }
            } else if b2 == None {
                b2 = Some(b);
                b2j = Some(j);
                writeln!(output, "YES").unwrap();
                for k in 1..j {
                    writeln!(output, "{} {}", k, j).unwrap();
                }
            } else if Some(b) == b2 {
                writeln!(output, "{} {}", 1, j).unwrap();
            } else {
                writeln!(output, "{} {}", 1, j).unwrap();
            }
        }
        if b2j == None {
            writeln!(output, "NO").unwrap();
        }

        //
    }

    #[allow(dead_code)]
    fn alternative<R, W>(input: &mut Input<R>, output: &mut W)
    where
        R: BufRead,
        W: Write,
    {
        let _ = input;
        let _ = output;
        panic!()
    }

    #[cfg(test)]
    #[test]
    fn test_example() {
        let output = |i| output_for(|i, o| solution(i, o), MODE, i);
        assert_eq!(
            output(
                "
                4
                5
                1 2 2 1 3
                3
                1 1 1
                4
                1 1000 101 1000
                4
                1 2 3 4
                "
            ),
            "
            YES
            1 2
            1 3
            2 4
            1 5
            NO
            YES
            1 2
            1 3
            1 4
            YES
            1 2
            1 3
            1 4
            "
            .reformat_with_trim(),
        );
    }

    #[cfg(test)]
    #[test]
    fn test_custom() {
        let output = |i| output_for(|i, o| solution(i, o), Mode::Single, i);
        assert_eq!(
            output("11 1 1 1 2 2 1 1 2 2 3 3"),
            "YES\n1 4\n2 4\n3 4\n1 5\n4 6\n4 7\n1 8\n1 9\n1 10\n1 11\n"
        );
    }
}

#[cfg(test)]
mod example {
    use crate::input::Input;
    #[allow(unused_imports)]
    use crate::util::*;
    use crate::Mode;
    use std::io::{BufRead, Write};

    pub const MODE: Mode = Mode::Multiple;

    pub fn solution<R, W>(input: &mut Input<R>, output: &mut W)
    where
        R: BufRead,
        W: Write,
    {
        let n: usize = input.next();
        let sum: i64 = (0..n).map(|_| -> i64 { input.next() }).sum();
        writeln!(output, "{}", sum).unwrap();
    }

    #[allow(dead_code)]
    fn alternative<R, W>(input: &mut Input<R>, output: &mut W)
    where
        R: BufRead,
        W: Write,
    {
        let n: usize = input.next();
        let mut sum: i64 = 0;
        for _ in 0..n {
            let next: i64 = input.next();
            sum += next;
        }
        writeln!(output, "{}", sum).unwrap();
    }

    #[ignore]
    #[cfg(test)]
    #[test]
    fn test_example() {
        let output = |i| output_for(|i, o| solution(i, o), MODE, i);
        assert_eq!(
            output(
                "
                    5
                    1 1
                    2 2 3
                    3 4 5 6
                    4 7 8 9 10
                    5 11 12 13 14 15
                "
            ),
            "
                    1
                    5
                    15
                    34
                    65
            "
            .reformat_with_trim(),
        );
    }

    #[ignore]
    #[cfg(test)]
    #[test]
    fn test_custom() {
        let output = |i| output_for(|i, o| solution(i, o), Mode::Single, i);
        assert_eq!(output("5 0 1 2 3 4"), "10\n");
    }

    #[allow(dead_code)]
    fn check_matched_output(input: &str) {
        assert_eq!(
            output_for(|input, output| solution(input, output), Mode::Single, input),
            output_for(
                |input, output| alternative(input, output),
                Mode::Single,
                input
            )
        );
    }

    #[ignore]
    #[cfg(test)]
    #[test]
    fn test_rand() {
        use rand::Rng;

        const N_MAX: usize = 100;
        const AI_MIN_INCL: i64 = 1;
        const AI_MAX_INCL: i64 = 10000;

        let mut rng = rand::thread_rng();
        let num_cases = 16;
        let mut input = format!("{} ", num_cases);
        for _ in 0..num_cases {
            let n = rng.gen_range(0, N_MAX);
            let m = rng.gen_range(0, 4);
            input += &format!("{} {} ", n, m);
            for _ in 0..n {
                let ai = rng.gen_range(AI_MIN_INCL, AI_MAX_INCL + 1);
                input += &format!("{} ", ai);
            }
        }
        check_matched_output(&input);
    }

    #[ignore]
    #[cfg(test)]
    #[test]
    fn test_perf() {
        use rand::rngs::StdRng;
        use rand::Rng;
        use rand::SeedableRng;
        use std::time::Instant;

        const T_MAX: usize = 1000;
        const N_MAX: usize = 100;
        const AI_MIN_INCL: i64 = 1;
        const AI_MAX_INCL: i64 = 10000;

        let mut rng = StdRng::seed_from_u64(123);
        let mut input = format!("{} ", T_MAX);
        for _ in 0..T_MAX {
            let n = N_MAX;
            let m = rng.gen_range(0, 4);
            input += &format!("{} {} ", n, m);
            for _ in 0..n {
                let ai = rng.gen_range(AI_MIN_INCL, AI_MAX_INCL + 1);
                input += &format!("{} ", ai);
            }
        }
        let now = Instant::now();
        check_matched_output(&input);
        let dt_ms = now.elapsed().as_millis() / 2;
        let dt_ns = now.elapsed().as_nanos() / 2;
        let max_ms = 100;
        if dt_ms > max_ms {
            panic!(
                "Time limit exceeded: real: {}ms({}ns) > {}ms",
                dt_ms, dt_ns, max_ms
            );
        }
    }
}

#[allow(dead_code)]
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum Mode {
    Single,   // If only the single test case is expected
    Multiple, // If multiple test cases are expected
}

pub fn main() {
    use std::io::Write;
    use std::io::{self, BufReader, BufWriter};

    use crate::input::Input;
    use crate::task::solution;
    use crate::task::MODE;
    use crate::util::solve;

    let mut input = Input::new(BufReader::new(io::stdin()));
    let mut output = BufWriter::new(io::stdout());
    solve(solution, MODE, &mut input, &mut output);
    output.flush().unwrap();
}

#[cfg(test)]
mod target {
    #[test]
    fn test_32bit_target() {
        use std::mem::size_of;
        assert_eq!(size_of::<usize>(), 4, "Codeforces use 32-bit targets");
    }
}

mod util {
    use std::io::BufRead;
    use std::io::Write;

    use crate::input::Input;
    use crate::Mode;

    pub fn solve<F, R, W>(func: F, mode: Mode, input: &mut Input<R>, output: &mut W)
    where
        F: Fn(&mut Input<R>, &mut W),
        R: BufRead,
        W: Write,
    {
        match mode {
            Mode::Single => {
                func(input, output);
                output.flush().unwrap();
            }
            Mode::Multiple => {
                let n: usize = input.next();
                for _ in 0..n {
                    func(input, output);
                    output.flush().unwrap();
                }
            }
        }
    }

    #[allow(dead_code)]
    pub fn output_for<F>(func: F, mode: Mode, input: &str) -> String
    where
        F: Fn(&mut Input<&[u8]>, &mut Vec<u8>),
    {
        let mut input = Input::new(input.as_bytes());
        let mut output: Vec<u8> = Vec::new();
        solve(func, mode, &mut input, &mut output);
        std::str::from_utf8(&output).unwrap().to_string()
    }

    pub trait ReformatWithTrim {
        fn reformat_with_trim(self) -> String;
    }

    impl ReformatWithTrim for &str {
        fn reformat_with_trim(self) -> String {
            let lines: Vec<String> = self
                .trim()
                .lines()
                .map(|line| line.trim_start().to_string())
                .collect();
            lines.join("\n") + "\n"
        }
    }
}

mod input {
    use std::collections::VecDeque;
    use std::io::BufRead;

    pub struct Input<R> {
        input: R,
        buffer: VecDeque<String>,
    }

    impl<R> Input<R> {
        pub fn new(input: R) -> Self {
            Self {
                input,
                buffer: VecDeque::new(),
            }
        }

        pub fn next<T: std::str::FromStr>(&mut self) -> T
        where
            R: BufRead,
        {
            while self.buffer.is_empty() {
                let mut line = String::new();
                self.input.read_line(&mut line).ok();
                for word in line.split_whitespace() {
                    self.buffer.push_back(word.to_string())
                }
            }
            let front = self.buffer.pop_front().unwrap();
            front.parse::<T>().ok().unwrap()
        }
    }
}

mod num {
    use core::marker::PhantomData;
    use std::ops::{Add, Mul, Neg, Rem, Sub};

    pub trait Zero {
        fn zero() -> Self;
        fn is_zero(&self) -> bool;
    }

    pub trait One {
        fn one() -> Self;
        fn is_one(&self) -> bool;
    }

    pub trait Abs {
        fn abs(self) -> Self;
    }

    pub trait RemEuclid {
        fn rem_euclid(self, divisor: Self) -> Self;
    }

    pub trait ModNeg {
        fn mod_neg(self, divisor: Self) -> Self;
    }

    pub trait ModAdd {
        fn mod_add(self, rhs: Self, divisor: Self) -> Self;
    }

    pub trait ModSub {
        fn mod_sub(self, rhs: Self, divisor: Self) -> Self;
    }

    pub trait ModMul {
        fn mod_mul(self, rhs: Self, divisor: Self) -> Self;
    }

    macro_rules! impl_zero_one_abs_for {
        ($type:ty) => {
            impl Zero for $type {
                fn zero() -> Self {
                    0
                }
                fn is_zero(&self) -> bool {
                    *self == 0
                }
            }

            impl One for $type {
                fn one() -> Self {
                    1
                }
                fn is_one(&self) -> bool {
                    *self == 1
                }
            }

            impl Abs for $type {
                fn abs(self) -> Self {
                    self
                }
            }

            impl RemEuclid for $type {
                #[allow(unused_comparisons)]
                fn rem_euclid(self, divisor: Self) -> Self {
                    self.rem_euclid(divisor)
                }
            }
        };
    }

    impl_zero_one_abs_for!(u8);
    impl_zero_one_abs_for!(u16);
    impl_zero_one_abs_for!(u32);
    impl_zero_one_abs_for!(u64);
    impl_zero_one_abs_for!(u128);
    impl_zero_one_abs_for!(usize);
    impl_zero_one_abs_for!(i8);
    impl_zero_one_abs_for!(i16);
    impl_zero_one_abs_for!(i32);
    impl_zero_one_abs_for!(i64);
    impl_zero_one_abs_for!(i128);
    impl_zero_one_abs_for!(isize);

    impl<T> ModNeg for T
    where
        T: Sub<T, Output = T> + Zero,
    {
        fn mod_neg(self, divisor: Self) -> Self {
            if self.is_zero() {
                self
            } else {
                divisor - self
            }
        }
    }

    impl<T> ModAdd for T
    where
        T: Add<T, Output = T> + PartialOrd + Sub<T, Output = T> + Zero,
    {
        fn mod_add(self, rhs: Self, divisor: Self) -> Self {
            let value = self + rhs;
            if value >= divisor {
                value - divisor
            } else {
                value
            }
        }
    }

    impl<T> ModSub for T
    where
        T: Add<T, Output = T> + PartialOrd + Sub<T, Output = T> + Zero,
    {
        fn mod_sub(self, rhs: Self, divisor: Self) -> Self {
            if self >= rhs {
                self - rhs
            } else {
                self + divisor - rhs
            }
        }
    }

    impl<T> ModMul for T
    where
        T: Add<T, Output = T> + Mul<T, Output = T> + PartialOrd + Rem<Output = T> + Zero,
    {
        fn mod_mul(self, rhs: Self, divisor: Self) -> Self {
            (self * rhs) % divisor
        }
    }

    trait ModDivisor {
        type Output;
        fn get() -> Self::Output;
    }

    #[derive(Clone, Copy, Debug, Default, Eq, Hash, Ord, PartialEq, PartialOrd)]
    struct ModValue<T, D>(T, PhantomData<D>);

    impl<T, D> ModValue<T, D>
    where
        D: ModDivisor<Output = T>,
    {
        #[allow(dead_code)]
        pub fn value(self) -> T {
            self.0
        }
    }

    impl<T, D> From<T> for ModValue<T, D>
    where
        T: RemEuclid,
        D: ModDivisor<Output = T>,
    {
        fn from(value: T) -> Self {
            Self(value.rem_euclid(D::get()), PhantomData)
        }
    }

    impl<T, D> Add for ModValue<T, D>
    where
        T: ModAdd,
        D: ModDivisor<Output = T>,
    {
        type Output = Self;

        fn add(self, other: Self) -> Self {
            Self(self.0.mod_add(other.0, D::get()), PhantomData)
        }
    }

    impl<T, D> Sub for ModValue<T, D>
    where
        T: ModSub,
        D: ModDivisor<Output = T>,
    {
        type Output = Self;

        fn sub(self, other: Self) -> Self {
            Self(self.0.mod_sub(other.0, D::get()), PhantomData)
        }
    }

    impl<T, D> Neg for ModValue<T, D>
    where
        T: ModNeg,
        D: ModDivisor<Output = T>,
    {
        type Output = Self;

        fn neg(self) -> Self {
            Self(self.0.mod_neg(D::get()), PhantomData)
        }
    }

    impl<T, D> Mul for ModValue<T, D>
    where
        T: ModMul,
        D: ModDivisor<Output = T>,
    {
        type Output = Self;

        fn mul(self, other: Self) -> Self {
            Self(self.0.mod_mul(other.0, D::get()), PhantomData)
        }
    }

    #[cfg(test)]
    #[test]
    #[ignore]
    fn test_mod_ops() {
        #[derive(Clone, Copy, Debug, Default, Eq, Hash, Ord, PartialEq, PartialOrd)]
        struct Div103<T>(PhantomData<T>);

        impl<T> ModDivisor for Div103<T>
        where
            T: From<u8>,
        {
            type Output = T;
            fn get() -> Self::Output {
                T::from(103u8)
            }
        }

        fn vmod<T>(value: T) -> ModValue<T, Div103<T>>
        where
            T: RemEuclid + From<u8>,
        {
            ModValue::from(value)
        }

        assert_eq!(vmod(10), vmod(10));
        assert_eq!(vmod(-10), vmod(93));

        assert_eq!(vmod(50) + vmod(10), vmod(60));
        assert_eq!(vmod(50) + vmod(40), vmod(90));
        assert_eq!(vmod(50) + vmod(80), vmod(27));
        assert_eq!(vmod(50) + vmod(102), vmod(49));
        assert_eq!(vmod(102) + vmod(102), vmod(101));

        assert_eq!(vmod(50) - vmod(10), vmod(40));
        assert_eq!(vmod(50) - vmod(40), vmod(10));
        assert_eq!(vmod(50) - vmod(80), vmod(73));
        assert_eq!(vmod(50) - vmod(102), vmod(51));
        assert_eq!(vmod(102) - vmod(102), vmod(0));

        assert_eq!(vmod(11) * vmod(22), vmod(36));
    }
}

mod lib {
    use std::ops::{Div, Mul, Rem, Sub};

    use crate::num::{Abs, One, Zero};

    // https://en.wikipedia.org/wiki/Euclidean_algorithm
    #[allow(dead_code)]
    pub fn gcd<T>(lhs: T, rhs: T) -> T
    where
        T: Abs + Clone + Rem<Output = T> + Zero,
    {
        if lhs.is_zero() {
            rhs.abs()
        } else {
            gcd(rhs % lhs.clone(), lhs)
        }
    }

    #[cfg(test)]
    #[test]
    #[ignore]
    fn test_gcd() {
        assert_eq!(gcd(1, 1), 1);
        assert_eq!(gcd(2, 3), 1);
        assert_eq!(gcd(6, 15), 3);
        assert_eq!(gcd(30, 105), 15);
    }

    #[allow(dead_code)]
    pub fn lcm<T>(lhs: T, rhs: T) -> T
    where
        T: Abs + Clone + Div<Output = T> + Mul<Output = T> + Rem<Output = T> + Zero,
    {
        lhs.clone() * rhs.clone() / gcd(lhs, rhs)
    }

    #[cfg(test)]
    #[test]
    #[ignore]
    fn test_lcm() {
        assert_eq!(lcm(1, 1), 1);
        assert_eq!(lcm(2, 3), 6);
        assert_eq!(lcm(6, 15), 30);
        assert_eq!(lcm(30, 105), 210);
    }

    #[allow(dead_code)]
    pub fn factorial_from_0_to_20(value: usize) -> u64 {
        let result: [u64; 21] = [
            1,
            1,
            2,
            6,
            24,
            120,
            720,
            5_040,
            40_320,
            362_880,
            3_628_800,
            39_916_800,
            479_001_600,
            6_227_020_800,
            87_178_291_200,
            1_307_674_368_000,
            20_922_789_888_000,
            355_687_428_096_000,
            6_402_373_705_728_000,
            121_645_100_408_832_000,
            2_432_902_008_176_640_000,
        ];
        result[value]
    }

    #[cfg(test)]
    #[test]
    #[ignore]
    fn test_factorial_from_0_to_20() {
        for j in 0..=20 {
            assert_eq!(factorial_from_0_to_20(j), factorial_slow(j as u64));
        }
    }

    #[allow(dead_code)]
    pub fn factorial_from_0_to_34(value: usize) -> u128 {
        let result: [u128; 35] = [
            1,
            1,
            2,
            6,
            24,
            120,
            720,
            5_040,
            40_320,
            362_880,
            3_628_800,
            39_916_800,
            479_001_600,
            6_227_020_800,
            87_178_291_200,
            1_307_674_368_000,
            20_922_789_888_000,
            355_687_428_096_000,
            6_402_373_705_728_000,
            121_645_100_408_832_000,
            2_432_902_008_176_640_000,
            51_090_942_171_709_440_000,
            1_124_000_727_777_607_680_000,
            25_852_016_738_884_976_640_000,
            620_448_401_733_239_439_360_000,
            15_511_210_043_330_985_984_000_000,
            403_291_461_126_605_635_584_000_000,
            10_888_869_450_418_352_160_768_000_000,
            304_888_344_611_713_860_501_504_000_000,
            8_841_761_993_739_701_954_543_616_000_000,
            265_252_859_812_191_058_636_308_480_000_000,
            8_222_838_654_177_922_817_725_562_880_000_000,
            263_130_836_933_693_530_167_218_012_160_000_000,
            8_683_317_618_811_886_495_518_194_401_280_000_000,
            295_232_799_039_604_140_847_618_609_643_520_000_000,
        ];
        result[value]
    }

    #[cfg(test)]
    #[test]
    #[ignore]
    fn test_factorial_from_0_to_34() {
        for j in 0..=34 {
            assert_eq!(factorial_from_0_to_34(j), factorial_slow(j as u128));
        }
    }

    #[allow(dead_code)]
    pub fn factorial_slow<T>(value: T) -> T
    where
        T: Clone + Mul<Output = T> + One + Sub<Output = T> + Zero,
    {
        if value.is_zero() || value.is_one() {
            T::one()
        } else {
            value.clone() * factorial_slow(value - T::one())
        }
    }

    #[cfg(test)]
    #[test]
    #[ignore]
    fn test_factorial_slow() {
        assert_eq!(factorial_slow(0), 1);
        assert_eq!(factorial_slow(1), 1);
        assert_eq!(factorial_slow(2), 2);
        assert_eq!(factorial_slow(3), 6);
        assert_eq!(factorial_slow(4), 24);
        assert_eq!(factorial_slow(5), 120);
    }

    #[allow(dead_code)]
    pub fn permutations(n: usize) -> u64 {
        // https://en.wikipedia.org/wiki/Permutation
        // n=3: 123 132 213 231 312 321
        // P_n = A^n_n = n! / (n - n)! = n!
        factorial_from_0_to_20(n)
    }

    #[cfg(test)]
    #[test]
    #[ignore]
    fn test_permutations() {
        assert_eq!(permutations(1), 1);
        assert_eq!(permutations(2), 2);
        assert_eq!(permutations(3), 6);
        assert_eq!(permutations(4), 24);
    }

    #[allow(dead_code)]
    pub fn k_permutations(k: usize, n: usize) -> u64 {
        // https://en.wikipedia.org/wiki/Permutation#k-permutations_of_n
        // n=3, k=1:   1   2   3
        // n=3, k=2:  12  21  13  31  23  32
        // n=3, k=3: 123 132 213 231 312 321
        // A^k_n = n! / (n - k)!
        factorial_from_0_to_20(n) / factorial_from_0_to_20(n - k)
    }

    #[cfg(test)]
    #[test]
    #[ignore]
    fn test_k_permutations() {
        assert_eq!(k_permutations(1, 4), 4);
        assert_eq!(k_permutations(2, 4), 12);
        assert_eq!(k_permutations(3, 4), 24);
        assert_eq!(k_permutations(4, 4), 24);
    }

    #[allow(dead_code)]
    pub fn combinations(k: usize, n: usize) -> u64 {
        // https://en.wikipedia.org/wiki/Combination
        // n=3, k=1:   1   2   3
        // n=3, k=2:  12  23  31
        // n=3, k=3: 123
        // C^k_n = n! / [k! (n - k)!] = n!
        factorial_from_0_to_20(n) / factorial_from_0_to_20(k) / factorial_from_0_to_20(n - k)
    }

    #[cfg(test)]
    #[test]
    #[ignore]
    fn test_combinations() {
        assert_eq!(combinations(1, 4), 4);
        assert_eq!(combinations(2, 4), 6);
        assert_eq!(combinations(3, 4), 4);
        assert_eq!(combinations(4, 4), 1);
    }

    #[allow(dead_code)]
    pub fn sequences(n: u64) -> u64 {
        // n=3, k=1:   1   2   3
        // n=3, k=2:  12  23
        // n=3, k=3: 123
        n * (n + 1) / 2
    }

    #[cfg(test)]
    #[test]
    #[ignore]
    fn test_sequences() {
        assert_eq!(sequences(1), 1);
        assert_eq!(sequences(2), 3);
        assert_eq!(sequences(3), 6);
        assert_eq!(sequences(4), 10);
    }

    #[allow(dead_code)]
    pub fn mod_add_i64(lhs: i64, rhs: i64, vmod: i64) -> i64 {
        let value = lhs + rhs;
        if value >= vmod {
            value - vmod
        } else if value < 0 {
            value + vmod
        } else {
            value
        }
    }

    #[cfg(test)]
    #[test]
    #[ignore]
    fn test_mod_add_i64() {
        assert_eq!(mod_add_i64(50, 40, 103), 90);
        assert_eq!(mod_add_i64(50, 80, 103), 27);
        assert_eq!(mod_add_i64(50, -40, 103), 10);
        assert_eq!(mod_add_i64(50, -80, 103), 73);
    }

    #[allow(dead_code)]
    pub fn mod_add_usize(lhs: usize, rhs: usize, vmod: usize) -> usize {
        let value = lhs + rhs;
        if value < vmod {
            value
        } else {
            value - vmod
        }
    }

    #[cfg(test)]
    #[test]
    #[ignore]
    fn test_mod_add_usize() {
        assert_eq!(mod_add_usize(50, 10, 103), 60);
        assert_eq!(mod_add_usize(50, 40, 103), 90);
        assert_eq!(mod_add_usize(50, 80, 103), 27);
        assert_eq!(mod_add_usize(50, 102, 103), 49);
        assert_eq!(mod_add_usize(102, 102, 103), 101);
    }

    #[allow(dead_code)]
    pub fn mod_sub_usize(lhs: usize, rhs: usize, vmod: usize) -> usize {
        if lhs >= rhs {
            lhs - rhs
        } else {
            lhs + vmod - rhs
        }
    }

    #[cfg(test)]
    #[test]
    #[ignore]
    fn test_mod_sub_usize() {
        assert_eq!(mod_sub_usize(50, 10, 103), 40);
        assert_eq!(mod_sub_usize(50, 40, 103), 10);
        assert_eq!(mod_sub_usize(50, 80, 103), 73);
        assert_eq!(mod_sub_usize(50, 102, 103), 51);
        assert_eq!(mod_sub_usize(102, 102, 103), 0);
    }

    pub trait InsertionSort {
        type Item;
        fn insertion_sort(&mut self)
        where
            Self::Item: Ord;
        fn insertion_sort_by<F>(&mut self, compare: F)
        where
            F: FnMut(&Self::Item, &Self::Item) -> std::cmp::Ordering;
        fn insertion_sort_by_key<K, F>(&mut self, f: F)
        where
            F: FnMut(&Self::Item) -> K,
            K: Ord;
        fn non_solution_insertion_sort(&mut self)
        where
            Self::Item: Ord;
    }

    // Works faster on an array with a length of less than 32 elements
    impl<T> InsertionSort for [T]
    where
        T: Copy,
    {
        type Item = T;
        fn insertion_sort(&mut self)
        where
            Self::Item: Ord,
        {
            self.insertion_sort_by(|lhs, rhs| lhs.cmp(rhs));
        }
        fn insertion_sort_by<F>(&mut self, mut compare: F)
        where
            F: FnMut(&Self::Item, &Self::Item) -> std::cmp::Ordering,
        {
            use std::cmp::Ordering;
            for i in 1..self.len() {
                let key = self[i];
                let mut j = i - 1;
                if compare(&self[j], &key) == Ordering::Greater {
                    self[i] = self[j];
                    while j > 0 && compare(&self[j - 1], &key) == Ordering::Greater {
                        self[j] = self[j - 1];
                        j -= 1;
                    }
                    self[j] = key;
                }
            }
        }
        fn insertion_sort_by_key<K, F>(&mut self, mut f: F)
        where
            F: FnMut(&Self::Item) -> K,
            K: Ord,
        {
            self.insertion_sort_by(|lhs, rhs| f(lhs).cmp(&f(rhs)))
        }
        fn non_solution_insertion_sort(&mut self)
        where
            Self::Item: Ord,
        {
            for j in 1..self.len() {
                for i in (0..j).rev() {
                    if self[i] < self[i + 1] {
                        break;
                    }
                    self.swap(i, i + 1);
                }
            }
        }
    }

    #[cfg(test)]
    #[test]
    #[ignore]
    fn test_insertion_sort() {
        use rand::Rng;

        let mut rng = rand::thread_rng();
        for _ in 0..256 {
            let n = rng.gen_range(0, 256);
            let mut a: Vec<u64> = (0..n).map(|_| rng.gen_range(0, 65536)).collect();
            let mut b = a.clone();
            let mut c = a.clone();
            a.insertion_sort();
            b.non_solution_insertion_sort();
            c.sort();
            assert_eq!(a, c);
            assert_eq!(b, c);
        }
    }

    #[cfg(test)]
    #[test]
    #[ignore]
    fn test_insertion_sort_faster_on_small_arrays() {
        use rand::Rng;

        const SAMPLES: usize = 256;
        const MIN_LENGTH: usize = 2;
        const MAX_LENGTH: usize = 24;
        const NUM_ITERATIONS: usize = 64;
        const MIN_SUCCESS_RATE: f64 = 0.8;

        let mut rng = rand::thread_rng();
        let mut oks = 0;
        let mut fails = 0;
        for n in MIN_LENGTH..MAX_LENGTH {
            for _ in 0..NUM_ITERATIONS {
                let array: Vec<i64> = (0..n).map(|_| rng.gen_range(0, 65536)).collect();
                let sort_time = measure_sort_time(&array[..], SAMPLES);
                if sort_time.insertion_sort_time < sort_time.non_solution_insertion_sort_time
                    && sort_time.insertion_sort_time < sort_time.sort_time
                    && sort_time.insertion_sort_time < sort_time.sort_unstable_time
                {
                    oks += 1;
                } else {
                    fails += 1;
                }
            }
        }
        let success_rate = oks as f64 / (oks + fails) as f64;
        assert!(
            success_rate >= MIN_SUCCESS_RATE,
            "Success rate {} excees minimal success rate {}",
            success_rate,
            MIN_SUCCESS_RATE
        );
    }

    #[cfg(test)]
    #[test]
    #[ignore]
    fn test_insertion_sort_longer_on_large_arrays() {
        use rand::Rng;

        const SAMPLES: usize = 16;
        const MIN_LENGTH: usize = 256;
        const MAX_LENGTH: usize = 288;
        const NUM_ITERATIONS: usize = 4;
        const MIN_SUCCESS_RATE: f64 = 1.0;

        let mut rng = rand::thread_rng();
        let mut oks = 0;
        let mut fails = 0;
        for n in MIN_LENGTH..MAX_LENGTH {
            for _ in 0..NUM_ITERATIONS {
                let array: Vec<i64> = (0..n).map(|_| rng.gen_range(0, 65536)).collect();
                let sort_time = measure_sort_time(&array[..], SAMPLES);
                if sort_time.insertion_sort_time > sort_time.sort_time
                    && sort_time.insertion_sort_time > sort_time.sort_unstable_time
                {
                    oks += 1;
                } else {
                    fails += 1;
                }
            }
        }
        let success_rate = oks as f64 / (oks + fails) as f64;
        assert!(
            success_rate >= MIN_SUCCESS_RATE,
            "Success rate {} excees minimal success rate {}",
            success_rate,
            MIN_SUCCESS_RATE
        );
    }

    #[cfg(test)]
    struct SortTime {
        sort_time: u64,
        sort_unstable_time: u64,
        insertion_sort_time: u64,
        non_solution_insertion_sort_time: u64,
    }

    #[cfg(test)]
    fn measure_sort_time(slice: &[i64], samples: usize) -> SortTime {
        SortTime {
            sort_time: rdtsc_perf(
                || slice.to_vec(),
                |mut input| {
                    input.sort();
                    input
                },
                samples,
            ),
            sort_unstable_time: rdtsc_perf(
                || slice.to_vec(),
                |mut input| {
                    input.sort_unstable();
                    input
                },
                samples,
            ),
            insertion_sort_time: rdtsc_perf(
                || slice.to_vec(),
                |mut input| {
                    input.insertion_sort();
                    input
                },
                samples,
            ),
            non_solution_insertion_sort_time: rdtsc_perf(
                || slice.to_vec(),
                |mut input| {
                    input.non_solution_insertion_sort();
                    input
                },
                samples,
            ),
        }
    }

    #[cfg(test)]
    #[inline(never)]
    pub fn black_box<D>(input: D) -> D {
        unsafe {
            let output = std::ptr::read_volatile(&input);
            std::mem::forget(input);
            output
        }
    }

    #[cfg(test)]
    pub fn rdtsc_perf<I, O, S, R>(mut setup: S, mut routine: R, samples: usize) -> u64
    where
        S: FnMut() -> I,
        R: FnMut(I) -> O,
    {
        use std::sync::atomic::compiler_fence;
        use std::sync::atomic::Ordering::SeqCst;
        let mut min_time: u64 = std::u64::MAX;
        for _ in 0..samples {
            let input = setup();
            compiler_fence(SeqCst);
            #[cfg(target_pointer_width = "32")]
            let time_a = unsafe { core::arch::x86::_rdtsc() };
            #[cfg(target_pointer_width = "64")]
            let time_a = unsafe { core::arch::x86_64::_rdtsc() };
            compiler_fence(SeqCst);
            let output = routine(input);
            compiler_fence(SeqCst);
            #[cfg(target_pointer_width = "32")]
            let time_b = unsafe { core::arch::x86::_rdtsc() };
            #[cfg(target_pointer_width = "64")]
            let time_b = unsafe { core::arch::x86_64::_rdtsc() };
            compiler_fence(SeqCst);
            min_time = min_time.min(time_b - time_a);
            black_box(output);
        }
        min_time
    }
}


#[allow(unused_imports)]
use std::cmp::*;
#[allow(unused_imports)]
use std::collections::*;
use std::io::{Write, BufWriter};
// https://qiita.com/tanakh/items/0ba42c7ca36cd29d0ac8
macro_rules! input {
    ($($r:tt)*) => {
        let stdin = std::io::stdin();
        let mut bytes = std::io::Read::bytes(std::io::BufReader::new(stdin.lock()));
        let mut next = move || -> String{
            bytes.by_ref().map(|r|r.unwrap() as char)
                .skip_while(|c|c.is_whitespace())
                .take_while(|c|!c.is_whitespace())
                .collect()
        };
        input_inner!{next, $($r)*}
    };
}

macro_rules! input_inner {
    ($next:expr) => {};
    ($next:expr, ) => {};
    ($next:expr, $var:ident : $t:tt $($r:tt)*) => {
        let $var = read_value!($next, $t);
        input_inner!{$next $($r)*}
    };
}

macro_rules! read_value {
    ($next:expr, [graph1; $len:expr]) => {{
        let mut g = vec![vec![]; $len];
        let ab = read_value!($next, [(usize1, usize1)]);
        for (a, b) in ab {
            g[a].push(b);
            g[b].push(a);
        }
        g
    }};
    ($next:expr, ( $($t:tt),* )) => {
        ( $(read_value!($next, $t)),* )
    };
    ($next:expr, [ $t:tt ; $len:expr ]) => {
        (0..$len).map(|_| read_value!($next, $t)).collect::<Vec<_>>()
    };
    ($next:expr, chars) => {
        read_value!($next, String).chars().collect::<Vec<char>>()
    };
    ($next:expr, usize1) => (read_value!($next, usize) - 1);
    ($next:expr, [ $t:tt ]) => {{
        let len = read_value!($next, usize);
        read_value!($next, [$t; len])
    }};
    ($next:expr, $t:ty) => ($next().parse::<$t>().expect("Parse error"));
}

#[allow(unused)]
macro_rules! debug {
    ($($format:tt)*) => (write!(std::io::stderr(), $($format)*).unwrap());
}
#[allow(unused)]
macro_rules! debugln {
    ($($format:tt)*) => (writeln!(std::io::stderr(), $($format)*).unwrap());
}

fn solve() {
    let out = std::io::stdout();
    let mut out = BufWriter::new(out.lock());
    macro_rules! puts {
        ($($format:tt)*) => (let _ = write!(out,$($format)*););
    }
    #[allow(unused)]
    macro_rules! putvec {
        ($v:expr) => {
            for i in 0..$v.len() {
                puts!("{}{}", $v[i], if i + 1 == $v.len() {"\n"} else {" "});
            }
        }
    }
    input! {
        a: [[i64]],
    }
    for a in a {
        let n = a.len();
        let mut b = a.clone();
        b.dedup();
        if b.len() == 1 {
            puts!("NO\n");
            continue;
        }
        puts!("YES\n");
        let mut dif = 0;
        for i in 1..n {
            if a[0] != a[i] {
                dif = i;
                break;
            }
        }
        let mut edges = vec![(0, dif)];
        for i in 1..n {
            if i == dif {
                continue;
            }
            if a[0] != a[i] {
                edges.push((0, i));
            } else {
                edges.push((dif, i));
            }
        }
        for &(a, b) in &edges {
            puts!("{} {}\n", a + 1, b + 1);
        }
    }
}

fn main() {
    // In order to avoid potential stack overflow, spawn a new thread.
    let stack_size = 104_857_600; // 100 MB
    let thd = std::thread::Builder::new().stack_size(stack_size);
    thd.spawn(|| solve()).unwrap().join().unwrap();
}


pub trait Zero: PartialEq + Sized {
    fn zero() -> Self;
    #[inline]
    fn is_zero(&self) -> bool {
        self == &Self::zero()
    }
}
pub trait One: PartialEq + Sized {
    fn one() -> Self;
    #[inline]
    fn is_one(&self) -> bool {
        self == &Self::one()
    }
}
macro_rules ! zero_one_impls { ($ ({ $ Trait : ident $ method : ident $ ($ t : ty) *, $ e : expr }) *) => { $ ($ (impl $ Trait for $ t { # [inline] fn $ method () -> Self { $ e } }) *) * } ; }
zero_one_impls ! ({ Zero zero u8 u16 u32 u64 usize i8 i16 i32 i64 isize u128 i128 , 0 } { Zero zero f32 f64 , 0. } { One one u8 u16 u32 u64 usize i8 i16 i32 i64 isize u128 i128 , 1 } { One one f32 f64 , 1. }) ;
#[macro_export]
macro_rules ! min { ($ e : expr) => { $ e } ; ($ e : expr , $ ($ es : expr) ,+) => { std :: cmp :: min ($ e , min ! ($ ($ es) ,+)) } ; }
#[macro_export]
macro_rules ! chmin { ($ dst : expr , $ ($ src : expr) ,+) => { { let x = std :: cmp :: min ($ dst , min ! ($ ($ src) ,+)) ; $ dst = x ; } } ; }
#[macro_export]
macro_rules ! max { ($ e : expr) => { $ e } ; ($ e : expr , $ ($ es : expr) ,+) => { std :: cmp :: max ($ e , max ! ($ ($ es) ,+)) } ; }
#[macro_export]
macro_rules ! chmax { ($ dst : expr , $ ($ src : expr) ,+) => { { let x = std :: cmp :: max ($ dst , max ! ($ ($ src) ,+)) ; $ dst = x ; } } ; }
pub trait IterScan: Sized {
    type Output;
    fn scan<'a, I: Iterator<Item = &'a str>>(iter: &mut I) -> Option<Self::Output>;
}
pub trait MarkedIterScan: Sized {
    type Output;
    fn mscan<'a, I: Iterator<Item = &'a str>>(self, iter: &mut I) -> Option<Self::Output>;
}
#[derive(Clone, Debug)]
pub struct Scanner<'a> {
    iter: std::str::SplitAsciiWhitespace<'a>,
}
mod scanner_impls {
    use super::*;
    impl<'a> Scanner<'a> {
        #[inline]
        pub fn new(s: &'a str) -> Self {
            let iter = s.split_ascii_whitespace();
            Self { iter }
        }
        #[inline]
        pub fn scan<T: IterScan>(&mut self) -> <T as IterScan>::Output {
            <T as IterScan>::scan(&mut self.iter).expect("scan error")
        }
        #[inline]
        pub fn mscan<T: MarkedIterScan>(&mut self, marker: T) -> <T as MarkedIterScan>::Output {
            marker.mscan(&mut self.iter).expect("scan error")
        }
        #[inline]
        pub fn scan_vec<T: IterScan>(&mut self, size: usize) -> Vec<<T as IterScan>::Output> {
            (0..size)
                .map(|_| <T as IterScan>::scan(&mut self.iter).expect("scan error"))
                .collect()
        }
        #[inline]
        pub fn iter<'b, T: IterScan>(&'b mut self) -> ScannerIter<'a, 'b, T> {
            ScannerIter {
                inner: self,
                _marker: std::marker::PhantomData,
            }
        }
    }
    macro_rules ! iter_scan_impls { ($ ($ t : ty) *) => { $ (impl IterScan for $ t { type Output = Self ; # [inline] fn scan <'a , I : Iterator < Item = &'a str >> (iter : & mut I) -> Option < Self > { iter . next () ?. parse ::<$ t > () . ok () } }) * } ; }
    iter_scan_impls ! (char u8 u16 u32 u64 usize i8 i16 i32 i64 isize f32 f64 u128 i128 String) ;
    macro_rules ! iter_scan_tuple_impl { ($ ($ T : ident) *) => { impl <$ ($ T : IterScan) ,*> IterScan for ($ ($ T ,) *) { type Output = ($ (<$ T as IterScan >:: Output ,) *) ; # [inline] fn scan <'a , It : Iterator < Item = &'a str >> (_iter : & mut It) -> Option < Self :: Output > { Some (($ (<$ T as IterScan >:: scan (_iter) ?,) *)) } } } ; }
    iter_scan_tuple_impl!();
    iter_scan_tuple_impl!(A);
    iter_scan_tuple_impl ! (A B) ;
    iter_scan_tuple_impl ! (A B C) ;
    iter_scan_tuple_impl ! (A B C D) ;
    iter_scan_tuple_impl ! (A B C D E) ;
    iter_scan_tuple_impl ! (A B C D E F) ;
    iter_scan_tuple_impl ! (A B C D E F G) ;
    iter_scan_tuple_impl ! (A B C D E F G H) ;
    iter_scan_tuple_impl ! (A B C D E F G H I) ;
    iter_scan_tuple_impl ! (A B C D E F G H I J) ;
    iter_scan_tuple_impl ! (A B C D E F G H I J K) ;
    pub struct ScannerIter<'a, 'b, T> {
        inner: &'b mut Scanner<'a>,
        _marker: std::marker::PhantomData<fn() -> T>,
    }
    impl<'a, 'b, T: IterScan> Iterator for ScannerIter<'a, 'b, T> {
        type Item = <T as IterScan>::Output;
        #[inline]
        fn next(&mut self) -> Option<Self::Item> {
            <T as IterScan>::scan(&mut self.inner.iter)
        }
    }
}
pub mod marker {
    use super::*;
    use std::{iter::FromIterator, marker::PhantomData};
    #[derive(Debug, Copy, Clone)]
    pub struct Usize1;
    impl IterScan for Usize1 {
        type Output = usize;
        #[inline]
        fn scan<'a, I: Iterator<Item = &'a str>>(iter: &mut I) -> Option<Self::Output> {
            Some(<usize as IterScan>::scan(iter)?.checked_sub(1)?)
        }
    }
    #[derive(Debug, Copy, Clone)]
    pub struct Chars;
    impl IterScan for Chars {
        type Output = Vec<char>;
        #[inline]
        fn scan<'a, I: Iterator<Item = &'a str>>(iter: &mut I) -> Option<Self::Output> {
            Some(iter.next()?.chars().collect())
        }
    }
    #[derive(Debug, Copy, Clone)]
    pub struct CharsWithBase(pub char);
    impl MarkedIterScan for CharsWithBase {
        type Output = Vec<usize>;
        #[inline]
        fn mscan<'a, I: Iterator<Item = &'a str>>(self, iter: &mut I) -> Option<Self::Output> {
            Some(
                iter.next()?
                    .chars()
                    .map(|c| (c as u8 - self.0 as u8) as usize)
                    .collect(),
            )
        }
    }
    #[derive(Debug, Copy, Clone)]
    pub struct Collect<T: IterScan, B: FromIterator<<T as IterScan>::Output>> {
        size: usize,
        _marker: PhantomData<fn() -> (T, B)>,
    }
    impl<T: IterScan, B: FromIterator<<T as IterScan>::Output>> Collect<T, B> {
        pub fn new(size: usize) -> Self {
            Self {
                size,
                _marker: PhantomData,
            }
        }
    }
    impl<T: IterScan, B: FromIterator<<T as IterScan>::Output>> MarkedIterScan for Collect<T, B> {
        type Output = B;
        #[inline]
        fn mscan<'a, I: Iterator<Item = &'a str>>(self, iter: &mut I) -> Option<Self::Output> {
            Some(
                (0..self.size)
                    .map(|_| <T as IterScan>::scan(iter).expect("scan error"))
                    .collect::<B>(),
            )
        }
    }
}
#[derive(Clone, Debug)]
pub struct UnionFind {
    parents: Vec<isize>,
}
impl UnionFind {
    pub fn new(n: usize) -> Self {
        let parents = vec![-1; n];
        Self { parents }
    }
    pub fn find(&mut self, x: usize) -> usize {
        if self.parents[x] < 0 {
            x
        } else {
            let xx = self.parents[x] as usize;
            let y = self.find(xx);
            self.parents[x] = y as isize;
            y
        }
    }
    pub fn unite(&mut self, x: usize, y: usize) -> bool {
        use std::mem::swap;
        let mut x = self.find(x);
        let mut y = self.find(y);
        if x == y {
            return false;
        }
        if self.parents[x] > self.parents[y] {
            swap(&mut x, &mut y);
        }
        self.parents[x] += self.parents[y];
        self.parents[y] = x as isize;
        true
    }
    pub fn size(&mut self, x: usize) -> usize {
        let x = self.find(x);
        (-self.parents[x]) as usize
    }
    pub fn same(&mut self, x: usize, y: usize) -> bool {
        self.find(x) == self.find(y)
    }
    pub fn members(&mut self, x: usize) -> Vec<usize> {
        let root = self.find(x);
        (0..self.parents.len())
            .filter(|i| self.find(*i) == root)
            .collect::<Vec<usize>>()
    }
    pub fn roots(&mut self) -> Vec<usize> {
        (0..self.parents.len())
            .filter(|i| self.parents[*i] < 0)
            .collect::<Vec<usize>>()
    }
    pub fn all_group_members(&mut self) -> std::collections::HashMap<usize, Vec<usize>> {
        let mut groups_map = std::collections::HashMap::new();
        for x in 0..self.parents.len() {
            let r = self.find(x);
            groups_map
                .entry(r)
                .or_insert_with(|| Vec::with_capacity(self.size(r)))
                .push(x);
        }
        groups_map
    }
}
fn main() {
    #![allow(unused_imports, unused_macros)]
    use std::io::{stdin, stdout, BufWriter, Read as _, Write as _};
    let mut _in_buf = Vec::new();
    stdin().read_to_end(&mut _in_buf).expect("io error");
    let _in_buf = unsafe { String::from_utf8_unchecked(_in_buf) };
    let mut scanner = Scanner::new(&_in_buf);
    macro_rules ! scan { () => { scan ! (usize) } ; (($ ($ t : tt) ,*)) => { ($ (scan ! ($ t)) ,*) } ; ([$ t : tt ; $ len : expr]) => { (0 ..$ len) . map (| _ | scan ! ($ t)) . collect ::< Vec < _ >> () } ; ([$ t : ty ; $ len : expr]) => { scanner . scan_vec ::<$ t > ($ len) } ; ([$ t : ty]) => { scanner . iter ::<$ t > () } ; ({ $ e : expr }) => { scanner . mscan ($ e) } ; ($ t : ty) => { scanner . scan ::<$ t > () } ; }
    let _out = stdout();
    let mut _out = BufWriter::new(_out.lock());
    macro_rules ! print { ($ ($ arg : tt) *) => (:: std :: write ! (_out , $ ($ arg) *) . expect ("io error")) }
    macro_rules ! println { ($ ($ arg : tt) *) => (:: std :: writeln ! (_out , $ ($ arg) *) . expect ("io error")) }
    macro_rules! echo {
        ($ iter : expr) => {
            echo!($iter, '\n')
        };
        ($ iter : expr , $ sep : expr) => {
            let mut iter = $iter.into_iter();
            if let Some(item) = iter.next() {
                print!("{}", item);
            }
            for item in iter {
                print!("{}{}", $sep, item);
            }
            println!();
        };
    }
    let t = scan!();
    for _ in 0..t {
        let n = scan!();
        let a = scan!([usize; n]);
        if a.iter().all(|&x| x == a[0]) {
            println!("NO");
        } else {
            println!("YES");
            let mut uf = UnionFind::new(n);
            let x = 0;
            let y = (0..n).position(|y| a[y] != a[x]).unwrap();
            uf.unite(x, y);
            for i in 0..n {
                if a[x] != a[i] && uf.unite(x, i) {
                    println!("{} {}", x + 1, i + 1);
                }
                if a[y] != a[i] && uf.unite(y, i) {
                    println!("{} {}", y + 1, i + 1);
                }
            }
        }
    }
}


pub trait Zero: PartialEq + Sized {
    fn zero() -> Self;
    #[inline]
    fn is_zero(&self) -> bool {
        self == &Self::zero()
    }
}
pub trait One: PartialEq + Sized {
    fn one() -> Self;
    #[inline]
    fn is_one(&self) -> bool {
        self == &Self::one()
    }
}
macro_rules ! zero_one_impls { ($ ({ $ Trait : ident $ method : ident $ ($ t : ty) *, $ e : expr }) *) => { $ ($ (impl $ Trait for $ t { # [inline] fn $ method () -> Self { $ e } }) *) * } ; }
zero_one_impls ! ({ Zero zero u8 u16 u32 u64 usize i8 i16 i32 i64 isize u128 i128 , 0 } { Zero zero f32 f64 , 0. } { One one u8 u16 u32 u64 usize i8 i16 i32 i64 isize u128 i128 , 1 } { One one f32 f64 , 1. }) ;
#[macro_export]
macro_rules ! min { ($ e : expr) => { $ e } ; ($ e : expr , $ ($ es : expr) ,+) => { std :: cmp :: min ($ e , min ! ($ ($ es) ,+)) } ; }
#[macro_export]
macro_rules ! chmin { ($ dst : expr , $ ($ src : expr) ,+) => { { let x = std :: cmp :: min ($ dst , min ! ($ ($ src) ,+)) ; $ dst = x ; } } ; }
#[macro_export]
macro_rules ! max { ($ e : expr) => { $ e } ; ($ e : expr , $ ($ es : expr) ,+) => { std :: cmp :: max ($ e , max ! ($ ($ es) ,+)) } ; }
#[macro_export]
macro_rules ! chmax { ($ dst : expr , $ ($ src : expr) ,+) => { { let x = std :: cmp :: max ($ dst , max ! ($ ($ src) ,+)) ; $ dst = x ; } } ; }
pub trait IterScan: Sized {
    type Output;
    fn scan<'a, I: Iterator<Item = &'a str>>(iter: &mut I) -> Option<Self::Output>;
}
pub trait MarkedIterScan: Sized {
    type Output;
    fn mscan<'a, I: Iterator<Item = &'a str>>(self, iter: &mut I) -> Option<Self::Output>;
}
#[derive(Clone, Debug)]
pub struct Scanner<'a> {
    iter: std::str::SplitAsciiWhitespace<'a>,
}
mod scanner_impls {
    use super::*;
    impl<'a> Scanner<'a> {
        #[inline]
        pub fn new(s: &'a str) -> Self {
            let iter = s.split_ascii_whitespace();
            Self { iter }
        }
        #[inline]
        pub fn scan<T: IterScan>(&mut self) -> <T as IterScan>::Output {
            <T as IterScan>::scan(&mut self.iter).expect("scan error")
        }
        #[inline]
        pub fn mscan<T: MarkedIterScan>(&mut self, marker: T) -> <T as MarkedIterScan>::Output {
            marker.mscan(&mut self.iter).expect("scan error")
        }
        #[inline]
        pub fn scan_vec<T: IterScan>(&mut self, size: usize) -> Vec<<T as IterScan>::Output> {
            (0..size)
                .map(|_| <T as IterScan>::scan(&mut self.iter).expect("scan error"))
                .collect()
        }
        #[inline]
        pub fn iter<'b, T: IterScan>(&'b mut self) -> ScannerIter<'a, 'b, T> {
            ScannerIter {
                inner: self,
                _marker: std::marker::PhantomData,
            }
        }
    }
    macro_rules ! iter_scan_impls { ($ ($ t : ty) *) => { $ (impl IterScan for $ t { type Output = Self ; # [inline] fn scan <'a , I : Iterator < Item = &'a str >> (iter : & mut I) -> Option < Self > { iter . next () ?. parse ::<$ t > () . ok () } }) * } ; }
    iter_scan_impls ! (char u8 u16 u32 u64 usize i8 i16 i32 i64 isize f32 f64 u128 i128 String) ;
    macro_rules ! iter_scan_tuple_impl { ($ ($ T : ident) *) => { impl <$ ($ T : IterScan) ,*> IterScan for ($ ($ T ,) *) { type Output = ($ (<$ T as IterScan >:: Output ,) *) ; # [inline] fn scan <'a , It : Iterator < Item = &'a str >> (_iter : & mut It) -> Option < Self :: Output > { Some (($ (<$ T as IterScan >:: scan (_iter) ?,) *)) } } } ; }
    iter_scan_tuple_impl!();
    iter_scan_tuple_impl!(A);
    iter_scan_tuple_impl ! (A B) ;
    iter_scan_tuple_impl ! (A B C) ;
    iter_scan_tuple_impl ! (A B C D) ;
    iter_scan_tuple_impl ! (A B C D E) ;
    iter_scan_tuple_impl ! (A B C D E F) ;
    iter_scan_tuple_impl ! (A B C D E F G) ;
    iter_scan_tuple_impl ! (A B C D E F G H) ;
    iter_scan_tuple_impl ! (A B C D E F G H I) ;
    iter_scan_tuple_impl ! (A B C D E F G H I J) ;
    iter_scan_tuple_impl ! (A B C D E F G H I J K) ;
    pub struct ScannerIter<'a, 'b, T> {
        inner: &'b mut Scanner<'a>,
        _marker: std::marker::PhantomData<fn() -> T>,
    }
    impl<'a, 'b, T: IterScan> Iterator for ScannerIter<'a, 'b, T> {
        type Item = <T as IterScan>::Output;
        #[inline]
        fn next(&mut self) -> Option<Self::Item> {
            <T as IterScan>::scan(&mut self.inner.iter)
        }
    }
}
pub mod marker {
    use super::*;
    use std::{iter::FromIterator, marker::PhantomData};
    #[derive(Debug, Copy, Clone)]
    pub struct Usize1;
    impl IterScan for Usize1 {
        type Output = usize;
        #[inline]
        fn scan<'a, I: Iterator<Item = &'a str>>(iter: &mut I) -> Option<Self::Output> {
            Some(<usize as IterScan>::scan(iter)?.checked_sub(1)?)
        }
    }
    #[derive(Debug, Copy, Clone)]
    pub struct Chars;
    impl IterScan for Chars {
        type Output = Vec<char>;
        #[inline]
        fn scan<'a, I: Iterator<Item = &'a str>>(iter: &mut I) -> Option<Self::Output> {
            Some(iter.next()?.chars().collect())
        }
    }
    #[derive(Debug, Copy, Clone)]
    pub struct CharsWithBase(pub char);
    impl MarkedIterScan for CharsWithBase {
        type Output = Vec<usize>;
        #[inline]
        fn mscan<'a, I: Iterator<Item = &'a str>>(self, iter: &mut I) -> Option<Self::Output> {
            Some(
                iter.next()?
                    .chars()
                    .map(|c| (c as u8 - self.0 as u8) as usize)
                    .collect(),
            )
        }
    }
    #[derive(Debug, Copy, Clone)]
    pub struct Collect<T: IterScan, B: FromIterator<<T as IterScan>::Output>> {
        size: usize,
        _marker: PhantomData<fn() -> (T, B)>,
    }
    impl<T: IterScan, B: FromIterator<<T as IterScan>::Output>> Collect<T, B> {
        pub fn new(size: usize) -> Self {
            Self {
                size,
                _marker: PhantomData,
            }
        }
    }
    impl<T: IterScan, B: FromIterator<<T as IterScan>::Output>> MarkedIterScan for Collect<T, B> {
        type Output = B;
        #[inline]
        fn mscan<'a, I: Iterator<Item = &'a str>>(self, iter: &mut I) -> Option<Self::Output> {
            Some(
                (0..self.size)
                    .map(|_| <T as IterScan>::scan(iter).expect("scan error"))
                    .collect::<B>(),
            )
        }
    }
}
#[derive(Clone, Debug)]
pub struct UnionFind {
    parents: Vec<isize>,
}
impl UnionFind {
    pub fn new(n: usize) -> Self {
        let parents = vec![-1; n];
        Self { parents }
    }
    pub fn find(&mut self, x: usize) -> usize {
        if self.parents[x] < 0 {
            x
        } else {
            let xx = self.parents[x] as usize;
            let y = self.find(xx);
            self.parents[x] = y as isize;
            y
        }
    }
    pub fn unite(&mut self, x: usize, y: usize) -> bool {
        use std::mem::swap;
        let mut x = self.find(x);
        let mut y = self.find(y);
        if x == y {
            return false;
        }
        if self.parents[x] > self.parents[y] {
            swap(&mut x, &mut y);
        }
        self.parents[x] += self.parents[y];
        self.parents[y] = x as isize;
        true
    }
    pub fn size(&mut self, x: usize) -> usize {
        let x = self.find(x);
        (-self.parents[x]) as usize
    }
    pub fn same(&mut self, x: usize, y: usize) -> bool {
        self.find(x) == self.find(y)
    }
    pub fn members(&mut self, x: usize) -> Vec<usize> {
        let root = self.find(x);
        (0..self.parents.len())
            .filter(|i| self.find(*i) == root)
            .collect::<Vec<usize>>()
    }
    pub fn roots(&mut self) -> Vec<usize> {
        (0..self.parents.len())
            .filter(|i| self.parents[*i] < 0)
            .collect::<Vec<usize>>()
    }
    pub fn all_group_members(&mut self) -> std::collections::HashMap<usize, Vec<usize>> {
        let mut groups_map = std::collections::HashMap::new();
        for x in 0..self.parents.len() {
            let r = self.find(x);
            groups_map
                .entry(r)
                .or_insert_with(|| Vec::with_capacity(self.size(r)))
                .push(x);
        }
        groups_map
    }
}
fn main() {
    #![allow(unused_imports, unused_macros)]
    use std::io::{stdin, stdout, BufWriter, Read as _, Write as _};
    let mut _in_buf = Vec::new();
    stdin().read_to_end(&mut _in_buf).expect("io error");
    let _in_buf = unsafe { String::from_utf8_unchecked(_in_buf) };
    let mut scanner = Scanner::new(&_in_buf);
    macro_rules ! scan { () => { scan ! (usize) } ; (($ ($ t : tt) ,*)) => { ($ (scan ! ($ t)) ,*) } ; ([$ t : tt ; $ len : expr]) => { (0 ..$ len) . map (| _ | scan ! ($ t)) . collect ::< Vec < _ >> () } ; ([$ t : ty ; $ len : expr]) => { scanner . scan_vec ::<$ t > ($ len) } ; ([$ t : ty]) => { scanner . iter ::<$ t > () } ; ({ $ e : expr }) => { scanner . mscan ($ e) } ; ($ t : ty) => { scanner . scan ::<$ t > () } ; }
    let _out = stdout();
    let mut _out = BufWriter::new(_out.lock());
    macro_rules ! print { ($ ($ arg : tt) *) => (:: std :: write ! (_out , $ ($ arg) *) . expect ("io error")) }
    macro_rules ! println { ($ ($ arg : tt) *) => (:: std :: writeln ! (_out , $ ($ arg) *) . expect ("io error")) }
    macro_rules! echo {
        ($ iter : expr) => {
            echo!($iter, '\n')
        };
        ($ iter : expr , $ sep : expr) => {
            let mut iter = $iter.into_iter();
            if let Some(item) = iter.next() {
                print!("{}", item);
            }
            for item in iter {
                print!("{}{}", $sep, item);
            }
            println!();
        };
    }
    let t = scan!();
    for _ in 0..t {
        let n = scan!();
        let a = scan!([usize; n]);
        if a.iter().all(|&x| x == a[0]) {
            println!("NO");
        } else {
            println!("YES");
            let mut uf = UnionFind::new(n);
            let x = 0;
            let y = (0..n).position(|y| a[y] != a[x]).unwrap();
            uf.unite(x, y);
            println!("{} {}", x + 1, y + 1);
            for i in 0..n {
                if a[x] != a[i] && uf.unite(x, i) {
                    println!("{} {}", x + 1, i + 1);
                }
                if a[y] != a[i] && uf.unite(y, i) {
                    println!("{} {}", y + 1, i + 1);
                }
            }
            assert!(uf.roots().len() == 1);
        }
    }
}


pub trait Zero: PartialEq + Sized {
    fn zero() -> Self;
    #[inline]
    fn is_zero(&self) -> bool {
        self == &Self::zero()
    }
}
pub trait One: PartialEq + Sized {
    fn one() -> Self;
    #[inline]
    fn is_one(&self) -> bool {
        self == &Self::one()
    }
}
macro_rules ! zero_one_impls { ($ ({ $ Trait : ident $ method : ident $ ($ t : ty) *, $ e : expr }) *) => { $ ($ (impl $ Trait for $ t { # [inline] fn $ method () -> Self { $ e } }) *) * } ; }
zero_one_impls ! ({ Zero zero u8 u16 u32 u64 usize i8 i16 i32 i64 isize u128 i128 , 0 } { Zero zero f32 f64 , 0. } { One one u8 u16 u32 u64 usize i8 i16 i32 i64 isize u128 i128 , 1 } { One one f32 f64 , 1. }) ;
#[macro_export]
macro_rules ! min { ($ e : expr) => { $ e } ; ($ e : expr , $ ($ es : expr) ,+) => { std :: cmp :: min ($ e , min ! ($ ($ es) ,+)) } ; }
#[macro_export]
macro_rules ! chmin { ($ dst : expr , $ ($ src : expr) ,+) => { { let x = std :: cmp :: min ($ dst , min ! ($ ($ src) ,+)) ; $ dst = x ; } } ; }
#[macro_export]
macro_rules ! max { ($ e : expr) => { $ e } ; ($ e : expr , $ ($ es : expr) ,+) => { std :: cmp :: max ($ e , max ! ($ ($ es) ,+)) } ; }
#[macro_export]
macro_rules ! chmax { ($ dst : expr , $ ($ src : expr) ,+) => { { let x = std :: cmp :: max ($ dst , max ! ($ ($ src) ,+)) ; $ dst = x ; } } ; }
pub trait IterScan: Sized {
    type Output;
    fn scan<'a, I: Iterator<Item = &'a str>>(iter: &mut I) -> Option<Self::Output>;
}
pub trait MarkedIterScan: Sized {
    type Output;
    fn mscan<'a, I: Iterator<Item = &'a str>>(self, iter: &mut I) -> Option<Self::Output>;
}
#[derive(Clone, Debug)]
pub struct Scanner<'a> {
    iter: std::str::SplitAsciiWhitespace<'a>,
}
mod scanner_impls {
    use super::*;
    impl<'a> Scanner<'a> {
        #[inline]
        pub fn new(s: &'a str) -> Self {
            let iter = s.split_ascii_whitespace();
            Self { iter }
        }
        #[inline]
        pub fn scan<T: IterScan>(&mut self) -> <T as IterScan>::Output {
            <T as IterScan>::scan(&mut self.iter).expect("scan error")
        }
        #[inline]
        pub fn mscan<T: MarkedIterScan>(&mut self, marker: T) -> <T as MarkedIterScan>::Output {
            marker.mscan(&mut self.iter).expect("scan error")
        }
        #[inline]
        pub fn scan_vec<T: IterScan>(&mut self, size: usize) -> Vec<<T as IterScan>::Output> {
            (0..size)
                .map(|_| <T as IterScan>::scan(&mut self.iter).expect("scan error"))
                .collect()
        }
        #[inline]
        pub fn iter<'b, T: IterScan>(&'b mut self) -> ScannerIter<'a, 'b, T> {
            ScannerIter {
                inner: self,
                _marker: std::marker::PhantomData,
            }
        }
    }
    macro_rules ! iter_scan_impls { ($ ($ t : ty) *) => { $ (impl IterScan for $ t { type Output = Self ; # [inline] fn scan <'a , I : Iterator < Item = &'a str >> (iter : & mut I) -> Option < Self > { iter . next () ?. parse ::<$ t > () . ok () } }) * } ; }
    iter_scan_impls ! (char u8 u16 u32 u64 usize i8 i16 i32 i64 isize f32 f64 u128 i128 String) ;
    macro_rules ! iter_scan_tuple_impl { ($ ($ T : ident) *) => { impl <$ ($ T : IterScan) ,*> IterScan for ($ ($ T ,) *) { type Output = ($ (<$ T as IterScan >:: Output ,) *) ; # [inline] fn scan <'a , It : Iterator < Item = &'a str >> (_iter : & mut It) -> Option < Self :: Output > { Some (($ (<$ T as IterScan >:: scan (_iter) ?,) *)) } } } ; }
    iter_scan_tuple_impl!();
    iter_scan_tuple_impl!(A);
    iter_scan_tuple_impl ! (A B) ;
    iter_scan_tuple_impl ! (A B C) ;
    iter_scan_tuple_impl ! (A B C D) ;
    iter_scan_tuple_impl ! (A B C D E) ;
    iter_scan_tuple_impl ! (A B C D E F) ;
    iter_scan_tuple_impl ! (A B C D E F G) ;
    iter_scan_tuple_impl ! (A B C D E F G H) ;
    iter_scan_tuple_impl ! (A B C D E F G H I) ;
    iter_scan_tuple_impl ! (A B C D E F G H I J) ;
    iter_scan_tuple_impl ! (A B C D E F G H I J K) ;
    pub struct ScannerIter<'a, 'b, T> {
        inner: &'b mut Scanner<'a>,
        _marker: std::marker::PhantomData<fn() -> T>,
    }
    impl<'a, 'b, T: IterScan> Iterator for ScannerIter<'a, 'b, T> {
        type Item = <T as IterScan>::Output;
        #[inline]
        fn next(&mut self) -> Option<Self::Item> {
            <T as IterScan>::scan(&mut self.inner.iter)
        }
    }
}
pub mod marker {
    use super::*;
    use std::{iter::FromIterator, marker::PhantomData};
    #[derive(Debug, Copy, Clone)]
    pub struct Usize1;
    impl IterScan for Usize1 {
        type Output = usize;
        #[inline]
        fn scan<'a, I: Iterator<Item = &'a str>>(iter: &mut I) -> Option<Self::Output> {
            Some(<usize as IterScan>::scan(iter)?.checked_sub(1)?)
        }
    }
    #[derive(Debug, Copy, Clone)]
    pub struct Chars;
    impl IterScan for Chars {
        type Output = Vec<char>;
        #[inline]
        fn scan<'a, I: Iterator<Item = &'a str>>(iter: &mut I) -> Option<Self::Output> {
            Some(iter.next()?.chars().collect())
        }
    }
    #[derive(Debug, Copy, Clone)]
    pub struct CharsWithBase(pub char);
    impl MarkedIterScan for CharsWithBase {
        type Output = Vec<usize>;
        #[inline]
        fn mscan<'a, I: Iterator<Item = &'a str>>(self, iter: &mut I) -> Option<Self::Output> {
            Some(
                iter.next()?
                    .chars()
                    .map(|c| (c as u8 - self.0 as u8) as usize)
                    .collect(),
            )
        }
    }
    #[derive(Debug, Copy, Clone)]
    pub struct Collect<T: IterScan, B: FromIterator<<T as IterScan>::Output>> {
        size: usize,
        _marker: PhantomData<fn() -> (T, B)>,
    }
    impl<T: IterScan, B: FromIterator<<T as IterScan>::Output>> Collect<T, B> {
        pub fn new(size: usize) -> Self {
            Self {
                size,
                _marker: PhantomData,
            }
        }
    }
    impl<T: IterScan, B: FromIterator<<T as IterScan>::Output>> MarkedIterScan for Collect<T, B> {
        type Output = B;
        #[inline]
        fn mscan<'a, I: Iterator<Item = &'a str>>(self, iter: &mut I) -> Option<Self::Output> {
            Some(
                (0..self.size)
                    .map(|_| <T as IterScan>::scan(iter).expect("scan error"))
                    .collect::<B>(),
            )
        }
    }
}
#[derive(Clone, Debug)]
pub struct UnionFind {
    parents: Vec<isize>,
}
impl UnionFind {
    pub fn new(n: usize) -> Self {
        let parents = vec![-1; n];
        Self { parents }
    }
    pub fn find(&mut self, x: usize) -> usize {
        if self.parents[x] < 0 {
            x
        } else {
            let xx = self.parents[x] as usize;
            let y = self.find(xx);
            self.parents[x] = y as isize;
            y
        }
    }
    pub fn unite(&mut self, x: usize, y: usize) -> bool {
        use std::mem::swap;
        let mut x = self.find(x);
        let mut y = self.find(y);
        if x == y {
            return false;
        }
        if self.parents[x] > self.parents[y] {
            swap(&mut x, &mut y);
        }
        self.parents[x] += self.parents[y];
        self.parents[y] = x as isize;
        true
    }
    pub fn size(&mut self, x: usize) -> usize {
        let x = self.find(x);
        (-self.parents[x]) as usize
    }
    pub fn same(&mut self, x: usize, y: usize) -> bool {
        self.find(x) == self.find(y)
    }
    pub fn members(&mut self, x: usize) -> Vec<usize> {
        let root = self.find(x);
        (0..self.parents.len())
            .filter(|i| self.find(*i) == root)
            .collect::<Vec<usize>>()
    }
    pub fn roots(&mut self) -> Vec<usize> {
        (0..self.parents.len())
            .filter(|i| self.parents[*i] < 0)
            .collect::<Vec<usize>>()
    }
    pub fn all_group_members(&mut self) -> std::collections::HashMap<usize, Vec<usize>> {
        let mut groups_map = std::collections::HashMap::new();
        for x in 0..self.parents.len() {
            let r = self.find(x);
            groups_map
                .entry(r)
                .or_insert_with(|| Vec::with_capacity(self.size(r)))
                .push(x);
        }
        groups_map
    }
}
fn main() {
    #![allow(unused_imports, unused_macros)]
    use std::io::{stdin, stdout, BufWriter, Read as _, Write as _};
    let mut _in_buf = Vec::new();
    stdin().read_to_end(&mut _in_buf).expect("io error");
    let _in_buf = unsafe { String::from_utf8_unchecked(_in_buf) };
    let mut scanner = Scanner::new(&_in_buf);
    macro_rules ! scan { () => { scan ! (usize) } ; (($ ($ t : tt) ,*)) => { ($ (scan ! ($ t)) ,*) } ; ([$ t : tt ; $ len : expr]) => { (0 ..$ len) . map (| _ | scan ! ($ t)) . collect ::< Vec < _ >> () } ; ([$ t : ty ; $ len : expr]) => { scanner . scan_vec ::<$ t > ($ len) } ; ([$ t : ty]) => { scanner . iter ::<$ t > () } ; ({ $ e : expr }) => { scanner . mscan ($ e) } ; ($ t : ty) => { scanner . scan ::<$ t > () } ; }
    let _out = stdout();
    let mut _out = BufWriter::new(_out.lock());
    macro_rules ! print { ($ ($ arg : tt) *) => (:: std :: write ! (_out , $ ($ arg) *) . expect ("io error")) }
    macro_rules ! println { ($ ($ arg : tt) *) => (:: std :: writeln ! (_out , $ ($ arg) *) . expect ("io error")) }
    macro_rules! echo {
        ($ iter : expr) => {
            echo!($iter, '\n')
        };
        ($ iter : expr , $ sep : expr) => {
            let mut iter = $iter.into_iter();
            if let Some(item) = iter.next() {
                print!("{}", item);
            }
            for item in iter {
                print!("{}{}", $sep, item);
            }
            println!();
        };
    }
    let t = scan!();
    for _ in 0..t {
        let n = scan!();
        let a = scan!([usize; n]);
        if a.iter().all(|&x| x == a[0]) {
            println!("NO");
        } else {
            println!("YES");
            let mut uf = UnionFind::new(n);
            let x = 0;
            let y = (0..n).position(|y| a[y] != a[x]).unwrap();
            uf.unite(x, y);
            for i in 0..n {
                if a[x] != a[i] && uf.unite(x, i) {
                    println!("{} {}", x + 1, i + 1);
                }
                if a[y] != a[i] && uf.unite(y, i) {
                    println!("{} {}", y + 1, i + 1);
                }
            }
            assert!(uf.roots().len() == 1);
        }
    }
}


package main

import (
	"bufio"
	"fmt"
	"os"
)

var T, n int

var _r = bufio.NewReader(os.Stdin)
var _w = bufio.NewWriter(os.Stdout)

func main() {
	for _, _ = fmt.Fscan(_r, &T); T > 0; T-- {
		_, _ = fmt.Fscan(_r, &n)
		a := make([]int, n+1)
		for i := 1; i <= n; i++ {
			_, _ = fmt.Fscan(_r, &a[i])
		}

		pos := -1
		for i := 2; i <= n; i++ {
			if a[i] != a[1] {
				pos = i
				break
			}
		}
		if pos == -1 {
			_, _ = fmt.Fprintln(_w, "NO")
			_ = _w.Flush()
			continue
		}

		_, _ = fmt.Fprintln(_w, "YES")
		for i := 2; i <= n; i++ {
			if a[i] == a[1] {
				_, _ = fmt.Fprintln(_w, i, pos)
			} else {
				_, _ = fmt.Fprintln(_w, 1, i)
			}
		}
		_ = _w.Flush()
	}
}


package main

import (
	"bufio"
	"fmt"
	"os"
)

func main() {
	defer _w.Flush()
	t := ReadInt()
	for i := 0; i < t; i++ {
		n := ReadInt()
		a := ReadInts(n)
		solve(n, a)
	}
}

func solve(n int, a []int) {
	m := make(map[int][]int)
	maxSize := 0
	for i, ai := range a {
		m[ai] = append(m[ai], i+1)
		maxSize = Max(maxSize, len(m[ai]))
	}
	if maxSize == n {
		println("NO")
		return
	}

	println("YES")

	second := 0
	tmp := make([]int, 0)
	for i := 1; i < n; i++ {
		if a[i] == a[0] {
			tmp = append(tmp, i+1)
		} else {
			println(1, i+1)
			second = i + 1
		}
	}
	for i := 0; i < len(tmp); i++ {
		println(second, tmp[i])
	}
}

func Max(xs ...int) int {
	max := xs[0]
	for _, x := range xs[1:] {
		if max < x {
			max = x
		}
	}
	return max
}

var _r, _w = bufio.NewReader(os.Stdin), bufio.NewWriter(os.Stdout)

func print(a ...interface{})            { fmt.Fprint(_w, a...) }
func printf(f string, a ...interface{}) { fmt.Fprintf(_w, f, a...) }
func println(a ...interface{})          { fmt.Fprintln(_w, a...) }
func Scan(a ...interface{}) {
	if _, err := fmt.Fscan(_r, a...); err != nil {
		panic(err)
	}
}
func ReadString() (s string) { Scan(&s); return }
func ReadInt() (i int)       { Scan(&i); return }
func ReadInts(n int) (a []int) {
	for i := 0; i < n; i++ {
		a = append(a, ReadInt())
	}
	return
}
func ReadInt64() (i int64) { Scan(&i); return }
func ReadInt64s(n int) (a []int64) {
	for i := 0; i < n; i++ {
		a = append(a, ReadInt64())
	}
	return
}


package main

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

func main() {
	defer _w.Flush()
	t := ReadInt()
	for i := 0; i < t; i++ {
		n := ReadInt()
		a := ReadInts(n)
		solve(n, a)
	}
}

func solve(n int, a []int) {
	m := make(map[int][]int)
	maxSize := 0
	for i, ai := range a {
		m[ai] = append(m[ai], i+1)
		maxSize = Max(maxSize, len(m[ai]))
	}

	if maxSize*2-1 > n {
		println("NO")
		return
	}
	println("YES")

	type Gang struct {
		Districts []int
	}

	gangs := make([]*Gang, 0)
	for _, districts := range m {
		gangs = append(gangs, &Gang{districts})
	}
	sort.Slice(gangs, func(i, j int) bool {
		return len(gangs[i].Districts) > len(gangs[j].Districts)
	})

	ans := make([]int, 0)
	for len(ans) < n {
		for _, gang := range gangs {
			if len(gang.Districts) > 0 {
				ans = append(ans, gang.Districts[0])
				gang.Districts = gang.Districts[1:]
			}
		}
	}

	for i := 0; i < n-1; i++ {
		println(ans[i], ans[i+1])
	}
}

func Max(xs ...int) int {
	max := xs[0]
	for _, x := range xs[1:] {
		if max < x {
			max = x
		}
	}
	return max
}

var _r, _w = bufio.NewReader(os.Stdin), bufio.NewWriter(os.Stdout)

func print(a ...interface{})            { fmt.Fprint(_w, a...) }
func printf(f string, a ...interface{}) { fmt.Fprintf(_w, f, a...) }
func println(a ...interface{})          { fmt.Fprintln(_w, a...) }
func Scan(a ...interface{}) {
	if _, err := fmt.Fscan(_r, a...); err != nil {
		panic(err)
	}
}
func ReadString() (s string) { Scan(&s); return }
func ReadInt() (i int)       { Scan(&i); return }
func ReadInts(n int) (a []int) {
	for i := 0; i < n; i++ {
		a = append(a, ReadInt())
	}
	return
}
func ReadInt64() (i int64) { Scan(&i); return }
func ReadInt64s(n int) (a []int64) {
	for i := 0; i < n; i++ {
		a = append(a, ReadInt64())
	}
	return
}


package main

import (
	"bufio"
	"fmt"
	"os"
)

func main() {
	defer _w.Flush()
	t := ReadInt()
	for i := 0; i < t; i++ {
		n := ReadInt()
		a := ReadInts(n)
		solve(n, a)
	}
}

func solve(n int, a []int) {
	m := make(map[int][]int)
	maxSize := 0
	for i, ai := range a {
		m[ai] = append(m[ai], i+1)
		maxSize = Max(maxSize, len(m[ai]))
	}
	if maxSize == n {
		println("NO")
		return
	}

	println("YES")

	tmp := make([]int, 0)
	for i := 1; i < n; i++ {
		if a[i] == a[0] {
			tmp = append(tmp, i+1)
		} else {
			println(1, i+1)
		}
	}
	for i := 0; i < len(tmp); i++ {
		println(2, tmp[i])
	}
}

func Max(xs ...int) int {
	max := xs[0]
	for _, x := range xs[1:] {
		if max < x {
			max = x
		}
	}
	return max
}

var _r, _w = bufio.NewReader(os.Stdin), bufio.NewWriter(os.Stdout)

func print(a ...interface{})            { fmt.Fprint(_w, a...) }
func printf(f string, a ...interface{}) { fmt.Fprintf(_w, f, a...) }
func println(a ...interface{})          { fmt.Fprintln(_w, a...) }
func Scan(a ...interface{}) {
	if _, err := fmt.Fscan(_r, a...); err != nil {
		panic(err)
	}
}
func ReadString() (s string) { Scan(&s); return }
func ReadInt() (i int)       { Scan(&i); return }
func ReadInts(n int) (a []int) {
	for i := 0; i < n; i++ {
		a = append(a, ReadInt())
	}
	return
}
func ReadInt64() (i int64) { Scan(&i); return }
func ReadInt64s(n int) (a []int64) {
	for i := 0; i < n; i++ {
		a = append(a, ReadInt64())
	}
	return
}


package main

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

func main() {
	defer _w.Flush()
	t := ReadInt()
	for i := 0; i < t; i++ {
		n := ReadInt()
		a := ReadInts(n)
		solve(n, a)
	}
}

func solve(n int, a []int) {
	m := make(map[int][]int)
	maxSize := 0
	for i, ai := range a {
		m[ai] = append(m[ai], i+1)
		maxSize = Max(maxSize, len(m[ai]))
	}

	if maxSize*2-1 > n {
		println("NO")
		return
	}
	println("YES")

	type Gang struct {
		Districts []int
	}

	gangs := make([]*Gang, 0)
	for _, districts := range m {
		gangs = append(gangs, &Gang{districts})
	}
	sort.Slice(gangs, func(i, j int) bool {
		return len(gangs[i].Districts) > len(gangs[j].Districts)
	})

	ans := make([]int, 0)
	for len(ans) < n {
		c := 0
		for i := 0; i < len(gangs); i++ {
			gang := gangs[i]
			if len(gang.Districts) > 0 {
				c++
				ans = append(ans, gang.Districts[0])
				gang.Districts = gang.Districts[1:]
			}
			if c == 2 {
				break
			}
		}
	}

	for i := 0; i < n-1; i++ {
		println(ans[i], ans[i+1])
	}
}

func Max(xs ...int) int {
	max := xs[0]
	for _, x := range xs[1:] {
		if max < x {
			max = x
		}
	}
	return max
}

var _r, _w = bufio.NewReader(os.Stdin), bufio.NewWriter(os.Stdout)

func print(a ...interface{})            { fmt.Fprint(_w, a...) }
func printf(f string, a ...interface{}) { fmt.Fprintf(_w, f, a...) }
func println(a ...interface{})          { fmt.Fprintln(_w, a...) }
func Scan(a ...interface{}) {
	if _, err := fmt.Fscan(_r, a...); err != nil {
		panic(err)
	}
}
func ReadString() (s string) { Scan(&s); return }
func ReadInt() (i int)       { Scan(&i); return }
func ReadInts(n int) (a []int) {
	for i := 0; i < n; i++ {
		a = append(a, ReadInt())
	}
	return
}
func ReadInt64() (i int64) { Scan(&i); return }
func ReadInt64s(n int) (a []int64) {
	for i := 0; i < n; i++ {
		a = append(a, ReadInt64())
	}
	return
}


package main

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

func solve() {
	t := readInt()
	for j := 0; j < t; j++ {
		n := readInt()
		a := readIntArray(n)
		solveSingle(a)
	}
}

func solveSingle(a []int) {
	n := len(a)
	connected := make(map[int]map[int]bool)
	for i := 0; i < n; i++ {
		connected[i] = make(map[int]bool)
	}
	for i := 0; i < n; i++ {
		for j := i + 1; j < n; j++ {
			if a[i] != a[j] && !connected[i][j] {
				connected[i][j] = true
				connected[j][i] = true
			}
		}
	}
	vis := make(map[int]bool, n)
	dfs(connected, 0, vis)
	if len(vis) == n {
		fmt.Println("YES")
		for v := 0; v < n; v++ {
			for u := range connected[v] {
				if v < u {
					fmt.Println(v + 1, u + 1)
				}
			}
		}
	} else {
		fmt.Println("NO")
	}
}

func dfs(connected map[int]map[int]bool, from int, vis map[int]bool) {
	vis[from] = true
	for next := range connected[from] {
		if !vis[next] {
			dfs(connected, next, vis)
		}
	}
}

var scanner *bufio.Scanner

func main() {
	scanner = bufio.NewScanner(os.Stdin)
	const MaxTokenLength = 1024 * 1024
	scanner.Buffer(make([]byte, 0, MaxTokenLength), MaxTokenLength)
	scanner.Split(bufio.ScanWords)
	solve()
}

// IO

func readString() string {
	scanner.Scan()
	return scanner.Text()
}

func readInt() int {
	val, _ := strconv.Atoi(readString())
	return val
}

func readInt64() int64 {
	v, _ := strconv.ParseInt(readString(), 10, 64)
	return v
}

func readIntArray(sz int) []int {
	a := make([]int, sz)
	for i := 0; i < sz; i++ {
		a[i] = readInt()
	}
	return a
}

func readInt64Array(n int) []int64 {
	res := make([]int64, n)
	for i := 0; i < n; i++ {
		res[i] = readInt64()
	}
	return res
}

func max(a, b int64) int64 {
	if a > b {
		return a
	}
	return b
}

func min(a, b int) int {
	if a < b {
		return a
	}
	return b
}


package main

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

func solve() {
	t := readInt()
	for j := 0; j < t; j++ {
		n := readInt()
		a := readIntArray(n)
		solveSingle(a)
	}
}

func solveSingle(a []int) {
	n := len(a)
	connected := make(map[int]map[int]bool)
	for i := 0; i < n; i++ {
		connected[i] = make(map[int]bool)
	}
	for i := 0; i < n; i++ {
		for j := i + 1; j < n; j++ {
			if a[i] != a[j] && !connected[i][j] {
				connected[i][j] = true
				connected[j][i] = true
				break
			}
		}
	}
	u := n - 1
	for j := 0; j < n; j++ {
		if a[u] != a[j] && !connected[u][j] {
			connected[u][j] = true
			connected[j][u] = true
			break
		}
	}
	vis := make(map[int]bool, n)
	dfs(connected, 0, vis)
	if len(vis) == n {
		fmt.Println("YES")
		for v := 0; v < n; v++ {
			for u := range connected[v] {
				if v < u {
					fmt.Println(v+1, u+1)
				}
			}
		}
	} else {
		fmt.Println("NO")
	}
}

func dfs(connected map[int]map[int]bool, from int, vis map[int]bool) {
	vis[from] = true
	for next := range connected[from] {
		if !vis[next] {
			dfs(connected, next, vis)
		}
	}
}

var scanner *bufio.Scanner

func main() {
	scanner = bufio.NewScanner(os.Stdin)
	const MaxTokenLength = 1024 * 1024
	scanner.Buffer(make([]byte, 0, MaxTokenLength), MaxTokenLength)
	scanner.Split(bufio.ScanWords)
	solve()
}

// IO

func readString() string {
	scanner.Scan()
	return scanner.Text()
}

func readInt() int {
	val, _ := strconv.Atoi(readString())
	return val
}

func readInt64() int64 {
	v, _ := strconv.ParseInt(readString(), 10, 64)
	return v
}

func readIntArray(sz int) []int {
	a := make([]int, sz)
	for i := 0; i < sz; i++ {
		a[i] = readInt()
	}
	return a
}

func readInt64Array(n int) []int64 {
	res := make([]int64, n)
	for i := 0; i < n; i++ {
		res[i] = readInt64()
	}
	return res
}

func max(a, b int64) int64 {
	if a > b {
		return a
	}
	return b
}

func min(a, b int) int {
	if a < b {
		return a
	}
	return b
}


package main

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

func solve() {
	t := readInt()
	for j := 0; j < t; j++ {
		n := readInt()
		a := readIntArray(n)
		solveSingle(a)
	}
}

func solveSingle(a []int) {
	n := len(a)
	connected := make(map[int]map[int]bool)
	for i := 0; i < n; i++ {
		connected[i] = make(map[int]bool)
	}
	for i := 0; i < n; i++ {
		if len(connected[i]) > 0 {
			continue
		}
		for j := 0; j < n; j++ {
			if a[i] != a[j] && !connected[i][j] {
				connected[i][j] = true
				connected[j][i] = true
				break
			}
		}
	}
	u := n - 1
	if len(connected[u]) == 0 {
		for j := 0; j < n - 1; j++ {
			if a[u] != a[j] && !connected[u][j] {
				connected[u][j] = true
				connected[j][u] = true
				break
			}
		}
	}
	vis := make(map[int]bool, n)
	dfs(connected, 0, vis)
	if len(vis) == n {
		fmt.Println("YES")
		for v := 0; v < n; v++ {
			for u := range connected[v] {
				if v < u {
					fmt.Println(v+1, u+1)
				}
			}
		}
	} else {
		fmt.Println("NO")
	}
}

func dfs(connected map[int]map[int]bool, from int, vis map[int]bool) {
	vis[from] = true
	for next := range connected[from] {
		if !vis[next] {
			dfs(connected, next, vis)
		}
	}
}

var scanner *bufio.Scanner

func main() {
	scanner = bufio.NewScanner(os.Stdin)
	const MaxTokenLength = 1024 * 1024
	scanner.Buffer(make([]byte, 0, MaxTokenLength), MaxTokenLength)
	scanner.Split(bufio.ScanWords)
	solve()
}

// IO

func readString() string {
	scanner.Scan()
	return scanner.Text()
}

func readInt() int {
	val, _ := strconv.Atoi(readString())
	return val
}

func readInt64() int64 {
	v, _ := strconv.ParseInt(readString(), 10, 64)
	return v
}

func readIntArray(sz int) []int {
	a := make([]int, sz)
	for i := 0; i < sz; i++ {
		a[i] = readInt()
	}
	return a
}

func readInt64Array(n int) []int64 {
	res := make([]int64, n)
	for i := 0; i < n; i++ {
		res[i] = readInt64()
	}
	return res
}

func max(a, b int64) int64 {
	if a > b {
		return a
	}
	return b
}

func min(a, b int) int {
	if a < b {
		return a
	}
	return b
}


package main

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

func solve() {
	t := readInt()
	for j := 0; j < t; j++ {
		n := readInt()
		a := readIntArray(n)
		solveSingle(a)
	}
}

func solveSingle(a []int) {
	n := len(a)
	connected := make(map[int]map[int]bool)
	for i := 0; i < n; i++ {
		connected[i] = make(map[int]bool)
	}
	for i := 0; i < n; i++ {
		for j := i + 1; j < n; j++ {
			if a[i] != a[j] && !connected[i][j] {
				connected[i][j] = true
				connected[j][i] = true
				break
			}
		}
	}
	vis := make(map[int]bool, n)
	dfs(connected, 0, vis)
	if len(vis) == n {
		fmt.Println("YES")
		for v := 0; v < n; v++ {
			for u := range connected[v] {
				if v < u {
					fmt.Println(v + 1, u + 1)
				}
			}
		}
	} else {
		fmt.Println("NO")
	}
}

func dfs(connected map[int]map[int]bool, from int, vis map[int]bool) {
	vis[from] = true
	for next := range connected[from] {
		if !vis[next] {
			dfs(connected, next, vis)
		}
	}
}

var scanner *bufio.Scanner

func main() {
	scanner = bufio.NewScanner(os.Stdin)
	const MaxTokenLength = 1024 * 1024
	scanner.Buffer(make([]byte, 0, MaxTokenLength), MaxTokenLength)
	scanner.Split(bufio.ScanWords)
	solve()
}

// IO

func readString() string {
	scanner.Scan()
	return scanner.Text()
}

func readInt() int {
	val, _ := strconv.Atoi(readString())
	return val
}

func readInt64() int64 {
	v, _ := strconv.ParseInt(readString(), 10, 64)
	return v
}

func readIntArray(sz int) []int {
	a := make([]int, sz)
	for i := 0; i < sz; i++ {
		a[i] = readInt()
	}
	return a
}

func readInt64Array(n int) []int64 {
	res := make([]int64, n)
	for i := 0; i < n; i++ {
		res[i] = readInt64()
	}
	return res
}

func max(a, b int64) int64 {
	if a > b {
		return a
	}
	return b
}

func min(a, b int) int {
	if a < b {
		return a
	}
	return b
}


package main

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

func solve() {
	t := readInt()
	for j := 0; j < t; j++ {
		n := readInt()
		a := readIntArray(n)
		solveSingle(a)
	}
}

func solveSingle(a []int) {
	n := len(a)
	connected := make(map[int]map[int]bool)
	for i := 0; i < n; i++ {
		connected[i] = make(map[int]bool)
	}
	for i := 0; i < n; i++ {
		for j := i + 1; j < n; j++ {
			if a[i] != a[j] && !connected[i][j] {
				connected[i][j] = true
				connected[j][i] = true
				break
			}
		}
	}
	if len(connected[n - 1]) == 0 {
		u := n - 1
		for j := 0; j < n; j++ {
			if a[u] != a[j] && !connected[u][j] {
				connected[u][j] = true
				connected[j][u] = true
				break
			}
		}
	}
	vis := make(map[int]bool, n)
	dfs(connected, 0, vis)
	if len(vis) == n {
		fmt.Println("YES")
		for v := 0; v < n; v++ {
			for u := range connected[v] {
				if v < u {
					fmt.Println(v+1, u+1)
				}
			}
		}
	} else {
		fmt.Println("NO")
	}
}

func dfs(connected map[int]map[int]bool, from int, vis map[int]bool) {
	vis[from] = true
	for next := range connected[from] {
		if !vis[next] {
			dfs(connected, next, vis)
		}
	}
}

var scanner *bufio.Scanner

func main() {
	scanner = bufio.NewScanner(os.Stdin)
	const MaxTokenLength = 1024 * 1024
	scanner.Buffer(make([]byte, 0, MaxTokenLength), MaxTokenLength)
	scanner.Split(bufio.ScanWords)
	solve()
}

// IO

func readString() string {
	scanner.Scan()
	return scanner.Text()
}

func readInt() int {
	val, _ := strconv.Atoi(readString())
	return val
}

func readInt64() int64 {
	v, _ := strconv.ParseInt(readString(), 10, 64)
	return v
}

func readIntArray(sz int) []int {
	a := make([]int, sz)
	for i := 0; i < sz; i++ {
		a[i] = readInt()
	}
	return a
}

func readInt64Array(n int) []int64 {
	res := make([]int64, n)
	for i := 0; i < n; i++ {
		res[i] = readInt64()
	}
	return res
}

func max(a, b int64) int64 {
	if a > b {
		return a
	}
	return b
}

func min(a, b int) int {
	if a < b {
		return a
	}
	return b
}


package main

import (
	"bufio"
	. "fmt"
	"io"
	"os"
)

// github.com/EndlessCheng/codeforces-go
func run(_r io.Reader, _w io.Writer) {
	in := bufio.NewReader(_r)
	out := bufio.NewWriter(_w)
	defer out.Flush()

	solve := func(Case int) {
		var n int
		Fscan(in, &n)
		a := make([]int, n)
		pos := map[int][]int{}
		for i := range a {
			Fscan(in, &a[i])
			pos[a[i]] = append(pos[a[i]], i)
		}
		if len(pos) == 1 {
			Fprintln(out, "NO")
			return
		}
		Fprintln(out, "YES")
		next := 0
		for v, ps := range pos {
			if v == a[0] {
				continue
			}
			next = v
			for _, p := range ps {
				Fprintln(out, pos[a[0]][0]+1, p+1)
			}
		}
		for _, p := range pos[a[0]][1:] {
			Fprintln(out, pos[next][0]+1, p+1)
		}
	}

	var t int
	Fscan(in, &t)
	for Case := 1; Case <= t; Case++ {
		solve(Case)
	}
}

func main() { run(os.Stdin, os.Stdout) }


package main

import (
	"bufio"
	"fmt"
	"io"
	"os"
	"sort"
)

type Gangster struct {
	Gang, City int
}

type Pair struct {
	First, Second int
}

var t int

func main() {
	var input io.Reader = bufio.NewReader(os.Stdin)

	fmt.Fscan(input, &t)

	for o := 0; o < t; o++ {
		var n int
		fmt.Fscan(input, &n)

		arr := make([]Gangster, n)
		for i := 0; i < n; i++ {
			fmt.Fscan(input, &arr[i].Gang)
			arr[i].City = i + 1
		}

		sort.Slice(arr, func(i, j int) bool {
			return arr[i].Gang < arr[j].Gang
		})

		ans := make([]Pair, 0)
		var last int

		for i := (n - 1); i >= 0; i-- {
			if arr[i].Gang == arr[0].Gang {
				last = i - 1
				break
			}

			var p Pair
			p.First = arr[0].City
			p.Second = arr[i].City

			ans = append(ans, p)
		}

		if len(ans) == 0 {
			fmt.Println("NO")
			continue
		}

		for i := last; i >= 0; i-- {
			var p Pair
			p.First = arr[i].City
			p.Second = arr[n-1].City
			ans = append(ans, p)
		}

		fmt.Println("YES")
		l := len(ans)
		for i := 0; i < l; i++ {
			fmt.Printf("%d %d\n", ans[i].First, ans[i].Second)
		}
	}
}