Problem:
MathJax.Hub.Config({ tex2jax: { inlineMath: [["$","$"], ["\\(","\\)"]], processEscapes: true }});

Binary Search Tree I

Search trees are data structures that support dynamic set operations including insert, search, delete and so on. Thus a search tree can be used both as a dictionary and as a priority queue.

Binary search tree is one of fundamental search trees. The keys in a binary search tree are always stored in such a way as to satisfy the following binary search tree property:

Let $x$ be a node in a binary search tree. If $y$ is a node in the left subtree of $x$, then $y.key \leq x.key$. If $y$ is a node in the right subtree of $x$, then $x.key \leq y.key$.

The following figure shows an example of the binary search tree.

For example, keys of nodes which belong to the left sub-tree of the node containing 80 are less than or equal to 80, and keys of nodes which belong to the right sub-tree are more than or equal to 80. The binary search tree property allows us to print out all the keys in the tree in sorted order by an inorder tree walk.

A binary search tree should be implemented in such a way that the binary search tree property continues to hold after modifications by insertions and deletions. A binary search tree can be represented by a linked data structure in which each node is an object. In addition to a key field and satellite data, each node contains fields left, right, and p that point to the nodes corresponding to its left child, its right child, and its parent, respectively.

To insert a new value $v$ into a binary search tree $T$, we can use the procedure insert as shown in the following pseudo code. The insert procedure is passed a node $z$ for which $z.key = v$, $z.left = NIL$, and $z.right = NIL$. The procedure modifies $T$ and some of the fields of $z$ in such a way that $z$ is inserted into an appropriate position in the tree.

1 insert(T, z)
2 y = NIL // parent of x
3 x = 'the root of T'
4 while x ≠ NIL
5 y = x // set the parent
6 if z.key < x.key
7 x = x.left // move to the left child
8 else
9 x = x.right // move to the right child
10 z.p = y
11
12 if y == NIL // T is empty
13 'the root of T' = z
14 else if z.key < y.key
15 y.left = z // z is the left child of y
16 else
17 y.right = z // z is the right child of y

Write a program which performs the following operations to a binary search tree $T$.

insert $k$: Insert a node containing $k$ as key into $T$.

print: Print the keys of the binary search tree by inorder tree walk and preorder tree walk respectively.

You should use the above pseudo code to implement the insert operation. $T$ is empty at the initial state.

Input

In the first line, the number of operations $m$ is given. In the following $m$ lines, operations represented by insert $k$ or print are given.

Output

For each print operation, print a list of keys obtained by inorder tree walk and preorder tree walk in a line respectively. Put a space character before each key.

Constraints

The number of operations $\leq 500,000$

The number of print operations $\leq 10$.

$-2,000,000,000 \leq key \leq 2,000,000,000$

The height of the binary tree does not exceed 100 if you employ the above pseudo code.

The keys in the binary search tree are all different.

Sample Input 1

8
insert 30
insert 88
insert 12
insert 1
insert 20
insert 17
insert 25
print

Sample Output 1

1 12 17 20 25 30 88
30 12 1 20 17 25 88

Reference

Introduction to Algorithms, Thomas H. Cormen, Charles E. Leiserson, Ronald L. Rivest, and Clifford Stein. The MIT Press.

Solution in C# (judge verdict: Accepted)

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Runtime.Serialization.Formatters.Binary;
using System.Text;
using Tree;
#if !DEBUG
    using System.IO;
#endif


public class Program {
    public static void Main() {
        #region SetAutoFlushIsFalse
#if !DEBUG
        var sw = new StreamWriter(Console.OpenStandardOutput()) { AutoFlush = false };
        Console.SetOut(sw);
#endif
        #endregion

        var n = ReadLib.ReadAsInt();

        var tree = new BinarySearchTree();
        for(int i = 0; i < n; i++) {
            var arrs = Console.ReadLine().Split(' ');
            if (arrs[0] == "print") {
                tree.GetInOrder().Select(d => $" {d}").ToList().ForEach(s => Console.Write(s));
                Console.WriteLine();
                tree.GetPreOrder().Select(d => $" {d}").ToList().ForEach(s => Console.Write(s));
                Console.WriteLine();
            } else {
                tree.Insert(int.Parse(arrs[1]));
            }
        }

        #region Flush
#if !DEBUG
        Console.Out.Flush();
        sw.Close();
#endif
        #endregion
    }

}

static class Calculation {
    
}

namespace Tree {
    /// <summary>UnionFind木</summary>
    public class UnionFind {
        Dictionary<int, int> nodeToRoot;
        Dictionary<int, int> rank; // その根が配下に何個nodeがぶら下がっているか

        public UnionFind(int n, int startAt = 0) {
            nodeToRoot = Enumerable.Range(startAt, n).ToDictionary(i => i, i => i);    // n個根を作る
            rank = Enumerable.Range(startAt, n).ToDictionary(i => i, i => 0);
        }

        /// <summary>根を得る</summary>
        public int GetRoot(int x) {
            if (nodeToRoot[x] == x) { // 渡されたノードが根
                return x;
            }
            nodeToRoot[x] = GetRoot(nodeToRoot[x]);  // parentの根を得てset。調べるたびに最適化。

            return nodeToRoot[x];
        }

        /// <summary>xとyの木を併合 => 根を同一にする</summary>
        public void Unite(int x, int y) {
            var rootX = GetRoot(x);
            var rootY = GetRoot(y);

            if (rootX == rootY) {
                return; // pass
            }

            if (rank[rootX] < rank[rootY]) {    // yをxへ併合
                nodeToRoot[rootX] = nodeToRoot[rootY];
            } else {
                nodeToRoot[rootX] = nodeToRoot[rootY];

                if (rank[rootX] == rank[rootY]) {
                    rank[rootX]++;  // yの下に配下が1つ追加される。
                }
            }
        }

        public bool AreSameRoot(int x, int y) {
            return GetRoot(x) == GetRoot(y);
        }
    }


    /// <summary>根付き木</summary>
    public class RootedTree {
        readonly Dictionary<int, Node> nodes;
        const int NIL = -1;
        int startAt;
        int nNode;

        class Node {
            /// <summary>親のID</summary>
            public int Parent { get; set; }
            /// <summary>子の最左端</summary>
            public int LeftChild { get; set; }
            /// <summary>右の兄弟</summary>
            public int RightBrother { get; set; }
            /// <summary>深さ</summary>
            public int Depth { get; set; }

            public Node() {
                Parent = NIL;
                LeftChild = NIL;
                RightBrother = NIL;
                Depth = 0;
            }
        }

        /// <summary>根付き木</summary>
        public RootedTree(int n, int startAt = 0) {
            this.nodes = Enumerable.Range(startAt, n).ToDictionary(i => i, i => new Node());
            this.startAt = startAt;
            this.nNode = n;
        }

        /// <summary>Nodeに子を追加</summary>
        public void SetChilds(int id, int[] childs) {
            if (childs.Length == 0) {
                return;
            }

            nodes[id].LeftChild = childs.First();

            for (int i = 0; i < childs.Length - 1; i++) {
                int childId = childs[i];
                nodes[childId].Parent = id;
                nodes[childId].RightBrother = childs[i + 1];
            }

            nodes[childs.Last()].Parent = id;
        }

        /// <summary>親Idを取得</summary>
        public int GetParentId(int id) {
            return nodes[id].Parent;
        }

        /// <summary>子のidを取得</summary>
        public int[] GetChilds(int id) {
            var childs = new List<int>();

            var child = nodes[id].LeftChild;
            while (child != NIL) {
                childs.Add(child);
                child = nodes[child].RightBrother;
            }

            return childs.ToArray();
        }

        int Root = NIL;
        public int GetRoot() {
            if (Root == NIL) {
                var current = nodes.First().Key;  // 何でもいい
                var parent = nodes[current].Parent;

                while (parent != NIL) {
                    current = parent;
                    parent = nodes[current].Parent;
                }

                Root = current;
            }
            return Root;
        }

        bool isSetedDepth = false;
        /// <summary>深さを取得</summary>
        public int GetDepth(int id) {
            if (!isSetedDepth) {
                var root = GetRoot();
                SetDepth(root, depth: 0);
                isSetedDepth = true;
            }

            var current = id;
            var parent = nodes[id].Parent;
            var depth = 0;
            while (parent != NIL) {
                current = parent;
                parent = nodes[current].Parent;
                depth++;
            }

            return depth;
        }

        private void SetDepth(int id, int depth) {
            var node = nodes[id];
            node.Depth = depth;

            if (node.RightBrother != NIL) {
                SetDepth(node.RightBrother, depth);
            }

            if (node.LeftChild != NIL) {
                SetDepth(node.LeftChild, depth + 1);
            }

        }

        public int NodesCount() {
            return nodes.Count();
        }
    }

    /// <summary>二分木</summary>
    public class BinaryTree {
        const int NIL = -1;
        readonly int startAt;
        readonly int nNode;
        class Node {
            public int Parent { get; set; }
            public int LeftChild { get; set; }
            public int RightChild { get; set; }

            public int Depth { get; set; }
            public int Height { get; set; }
            /// <summary>唯一の兄弟</summary>
            public int Sibling { get; set; }

            public Node() {
                Parent = NIL;
                LeftChild = NIL;
                RightChild = NIL;
                Sibling = NIL;

                Depth = 0;
                Height = 0;
            }
        }


        Dictionary<int, Node> nodes;
        public BinaryTree(int n, int startAt) {
            this.nodes = Enumerable.Range(startAt, n).ToDictionary(i => i, i => new Node());
            this.startAt = startAt;
            this.nNode = n;
        }

        /// <summary>
        /// 子をセットする
        /// </summary>
        /// <param name="id">ノードのID</param>
        /// <param name="left">左子ID。存在しない場合は-1</param>
        /// <param name="right">右子ID。存在しない場合は-1</param>
        public void SetChilds(int id, int left, int right) {
            nodes[id].LeftChild = left;
            nodes[id].RightChild = right;

            if (left != NIL) {
                nodes[left].Parent = id;
                nodes[left].Sibling = right;
            }

            if (right != NIL) {
                nodes[right].Parent = id;
                nodes[right].Sibling = left;
            }
        }

        /// <summary>Root</summary>
        int Root = NIL;
        public int GetRoot() {
            if (Root == NIL) {
                var current = nodes.First().Key;
                var parent = nodes[current].Parent;

                while (parent != NIL) {
                    current = parent;
                    parent = nodes[current].Parent;
                }

                Root = current;
            }

            return Root;
        }

        #region Depth
        bool isSetDepth = false;
        public int GetDepth(int id) {
            if (!isSetDepth) {
                var root = GetRoot();
                SetDepth(root, 0);
                isSetDepth = true;
            }

            return nodes[id].Depth;
        }

        private void SetDepth(int id, int depth) {
            nodes[id].Depth = depth;

            if (nodes[id].LeftChild != NIL) {
                SetDepth(nodes[id].LeftChild, depth + 1);
            }

            if (nodes[id].RightChild != NIL) {
                SetDepth(nodes[id].RightChild, depth + 1);
            }
        }
        #endregion

        #region Height
        bool isSetHeight = false;
        /// <summary>高さを得る</summary>
        public int GetHeight(int id) {
            if (!isSetHeight) {
                var root = GetRoot();
                SetHeight(root);
                isSetHeight = true;
            }

            return nodes[id].Height;
        }

        public int SetHeight(int id) {
            var node = nodes[id];
            int hLeft = 0;
            int hRight = 0;

            if (node.LeftChild != NIL) {
                hLeft = SetHeight(node.LeftChild) + 1;
            }

            if (node.RightChild != NIL) {
                hRight = SetHeight(node.RightChild) + 1;
            }

            node.Height = Math.Max(hLeft, hRight);
            return node.Height;
        }
        #endregion

        /// <summary>兄弟を得る</summary>
        public int GetSibling(int id) {
            return nodes[id].Sibling;
        }

        /// <summary>親IDを得る</summary>
        public int GetParent(int id) {
            return nodes[id].Parent;
        }

        public int[] GetChilds(int id) {
            var ids = new List<int>();
            if (nodes[id].LeftChild != NIL) {
                ids.Add(nodes[id].LeftChild);
            }

            if (nodes[id].RightChild != NIL) {
                ids.Add(nodes[id].RightChild);
            }

            return ids.ToArray();
        }

        /// <summary>左子を取得。存在しない時は-1</summary>
        public int GetLeft(int id) {
            return nodes[id].LeftChild;
        }

        /// <summary>右子を取得。存在しない時は-1</summary>
        public int GetRight(int id) {
            return nodes[id].RightChild;
        }

        public int NodesCount() {
            return nodes.Count();
        }

        #region 巡回
        private enum OrderType {
            Pre, In, Post
        }

        /// <summary>先行順巡回のNodeIdを取得</summary>
        public IEnumerable<int> GetPreOrder() {
            return Process(OrderType.Pre);
        }

        /// <summary>中間順巡回のNodeIdを取得</summary>
        public IEnumerable<int> GetInOrder() {
            return Process(OrderType.In);
        }

        /// <summary>後方順巡回のNodeIdを取得</summary>
        public IEnumerable<int> GetPostOrder() {
            return Process(OrderType.Post);
        }

        /// <summary>巡回を出力。O(N)</summary>
        private IEnumerable<int> Process(OrderType orderType) {
            var order = new List<int>();
            var stack = new Stack<int>();
            var passed = Enumerable.Range(startAt, nNode).ToDictionary(i => i, i => false); // 巡回済
            var orderAdded = Enumerable.Range(startAt, nNode).ToDictionary(i => i, i => false); // 処理済

            Action<int> addOrder = id => {
                if (!orderAdded[id]) {
                    order.Add(id);
                    orderAdded[id] = true;
                }
            };

            stack.Push(GetRoot());

            while (stack.Count > 0) {
                var current = stack.First();
                passed[current] = true;

                if (orderType == OrderType.Pre) {
                    addOrder(current); // 先行順巡回
                }

                int left = GetLeft(current);
                if (left != -1 && !passed[left]) {
                    stack.Push(left);
                    continue;
                }

                if (orderType == OrderType.In) {
                    addOrder(current); // 中間順巡回
                }

                int right = GetRight(current);
                if (right != -1 && !passed[right]) {
                    stack.Push(right);
                    continue;
                }

                if (orderType == OrderType.Post) {
                    addOrder(current);　 // 後方順巡回
                }

                stack.Pop();
            }

            return order;
        }
        #endregion
    }

    /// <summary>二分探索木</summary>
    public class BinarySearchTree {
        static readonly Node NIL = new Node(-1);
        class Node {
            public int Key { get; }
            public Node Parent { get; set; }
            public Node Left { get; set; }
            public Node Right { get; set; }

            public Node(int key) {
                this.Key = key;
                this.Parent = NIL;
                this.Left = NIL;
                this.Right = NIL;
            }
        }

        Node root = NIL;
        public void Insert(int key) {
            var z = new Node(key);

            var y = NIL;    // xの親
            var x = root;   // Treeの根

            while (x != NIL) {
                y = x;
                if (z.Key < x.Key) {
                    x = x.Left;
                } else {
                    x = x.Right;
                }
            }

            z.Parent = y;

            if (y == NIL) {
                root = z;
            } else if (z.Key < y.Key) {
                y.Left = z;
            } else {
                y.Right = z;
            }
        }

        public IEnumerable<int> GetInOrder() {
            var orderGetter = new OrderGetter();
            return orderGetter.GetInOrder(root);
        }

        public IEnumerable<int> GetPreOrder() {
            var orderGetter = new OrderGetter();
            return orderGetter.GetPreOrder(root);
        }

        class OrderGetter {
            private List<int> process = new List<int>();

            public IEnumerable<int> GetInOrder(Node root) {
                SetInOrder(root);
                return process;
            }

            public IEnumerable<int> GetPreOrder(Node root) {
                SetPreOrder(root);
                return process;
            }

            private void SetInOrder(Node node) {
                if (node == NIL) {
                    return;
                }
                
                SetInOrder(node.Left);
                process.Add(node.Key);
                SetInOrder(node.Right);
            }

            private void SetPreOrder(Node node) {
                if (node == NIL) {
                    return;
                }
                process.Add(node.Key);
                SetPreOrder(node.Left);
                SetPreOrder(node.Right);
            }
        }
        
    }
}

static class ReadLib {
    public static long ReadAsLong() {
        return long.Parse(Console.ReadLine());
    }

    public static int ReadAsInt() {
        return int.Parse(Console.ReadLine());
    }

    public static int[] ReadAsIntArray(int step = 0) {
        return Console.ReadLine().Split(' ').Select(s => int.Parse(s) + step).ToArray();
    }

    public static long[] ReadAsLongArray(int step = 0) {
        return Console.ReadLine().Split(' ').Select(s => long.Parse(s) + step).ToArray();
    }

    public static ulong[] ReadAsULongArray() {
        return Console.ReadLine().Split(' ').Select(s => ulong.Parse(s)).ToArray();
    }

    public static string[] ReadAsStringArray() {
        return Console.ReadLine().Split(' ');
    }

    public static int[] ReadNTimesAsInt(int n, int step = 0) {
        return Enumerable.Range(1, n).Select(s => int.Parse(Console.ReadLine()) + step).ToArray();
    }

    public static char[][] ReadNTimesAsCharArray(int n) {
        return Enumerable.Range(1, n).Select(i => Console.ReadLine().ToArray()).ToArray();
    }

    public static long[] ReadNTimesAsLong(int n, int step = 0) {
        return Enumerable.Range(1, n).Select(s => long.Parse(Console.ReadLine()) + step).ToArray();
    }

    public static int[][] ReadNTimesAsIntArray(int n, int step = 0) {
        return Enumerable.Range(1, n).Select(s => ReadAsIntArray(step)).ToArray();
    }

    public static string[] ReadNTimesAsString(int n) {
        return Enumerable.Range(1, n).Select(s => Console.ReadLine()).ToArray();
    }

}

static class WriteLib {
    public static void Write<T>(IEnumerable<T> ts) {
        ts.ToList().ForEach(s => Console.WriteLine(s));
    }
}

static class MyMath {
    /// <summary>階乗</summary>
    public static long Factorial(int n) {
        if (n == 0) {
            return 1;
        }

        return Permutation(n, 0);
    }

    public static long Permutation(int n, int k) {
        return Enumerable.Range(0, n - k).Select(i => n - i).Aggregate(1, (b, i) => b * i);
    }

    #region FullPower
    /// <summary>総乗、π</summary>
    public static long FullPower(IEnumerable<long> vs) {
        return vs.Aggregate(1L, (a, b) => a * b);
    }

    public static long FullPower(IEnumerable<int> vs) {
        return vs.Aggregate(1L, (a, b) => a * b);
    }
    #endregion

    /// <summary>最大公約数</summary>
    public static long Gcd(long item1, long item2) {
        var a = Math.Max(item1, item2);
        var b = Math.Min(item1, item2);

        while (true) {
            long mod;
            Math.DivRem(a, b, out mod);
            if (mod == 0) {
                break;
            }

            a = b;
            b = mod;
        }
        return b;
    }

    /// <summary>約分。最大公約数で割ったものを返す。</summary>
    public static Tuple<long, long> DeviedByGcd(long item1, long item2) {
        var gcd = Gcd(item1, item2);
        return new Tuple<long, long>(item1 / gcd, item2 / gcd);
    }

    public static long Lcm(int item1, int item2) {
        return Math.BigMul(item1, item2) / Gcd(item1, item2);
    }

    public static ModCombination ModCombination(int maxN, int mod = 1000000007) {
        return new ModCombination(maxN, mod);
    }

    /// <summary>a^n mod</summary>
    public static int ModPow(long a, long n, int mod = 1000000007) {
        long res = 1;
        long pow = a;

        while (n > 0) {
            if ((n & 1) == 1) {
                res = (pow * res) % mod;    // resにaをかける
            }

            pow = (pow * pow) % mod;    // 次のaはa^2
            n >>= 1;
        }

        return (int)res;
    }
}

static class MyMethod {
    /// <summary>数え上げて、key, 出現回数に変換</summary>
    public static Dictionary<T, int> CountUp<T>(IEnumerable<T> str) {
        return
            str
            .GroupBy(c => c)
            .Select(g => new KeyValuePair<T, int>(g.Key, g.Count()))
            .ToDictionary(e => e.Key, e => e.Value);
    }

    /// <summary>計数ソート</summary>
    public static int[] CountingSort(int[] aArr, int k) {
        int[] b, c;
        var n = aArr.Length;
        b = new int[n];
        c = Enumerable.Repeat(0, k + 1).ToArray();


        for (int i = 0; i < n; i++) {
            c[aArr[i]]++;
        }

        for (int i = 1; i <= k; i++) {
            c[i] += c[i - 1];
        }

        for (int i = n - 1; i >= 0; i--) {
            b[c[aArr[i]] - 1] = aArr[i];
            c[aArr[i]]--;
        }

        return b;
    }
}

/// <summary>無向グラフ</summary>
class UndirectedGraph {
    public Dictionary<int, List<int>> Graph { get; }

    /// <param name="graphArr">point1 to point2</param>
    /// <param name="n">グラフの全要素数</param>
    public UndirectedGraph(int[][] graphArr, int n) {
        Graph = new Dictionary<int, List<int>>();

        for (int i = 1; i <= n; i++) {
            Graph.Add(i, new List<int>());
        }

        foreach (var arr in graphArr) {
            Graph[arr[0]].Add(arr[1]);
            Graph[arr[1]].Add(arr[0]);
        }
    }
}
/// <summary>DeepCopyするクラス</summary>
class DeepCopier {
    BinaryFormatter b = new BinaryFormatter();
    public T DeepCopy<T>(T obj) {
        T result;
        using (var mem = new MemoryStream()) {
            b.Serialize(mem, obj); //  binaryFormatterによりobjをmemにserial化して書き出す
            mem.Position = 0; // memのpotisionを先頭に戻す
            result = (T)b.Deserialize(mem); // memの内容を読み取る。
        }
        return result;
    }
}

namespace Sort {
    static class MergeSort {
        public static long[] Sort(long[] arr) {
            return Sort(arr, 0, arr.Count());
        }
        // rightは+1されていることに注意
        private static long[] Merge(long[] sArr, int left, int mid, int right) {
            var n1 = mid - left;
            var n2 = right - mid;

            var lArr = new long[n1 + 1];
            var rArr = new long[n2 + 1];

            for (int i = 0; i < n1; i++) {
                lArr[i] = sArr[left + i];
            }
            lArr[n1] = int.MaxValue;

            for (int i = 0; i < n2; i++) {
                rArr[i] = sArr[mid + i];
            }
            rArr[n2] = int.MaxValue;

            int l = 0, r = 0;
            for (int k = left; k < right; k++) {
                if (lArr[l] <= rArr[r]) {
                    sArr[k] = lArr[l];
                    l++;
                } else {
                    sArr[k] = rArr[r];
                    r++;
                }
            }
            return sArr; // 要素数はright - left
        }

        private static long[] Sort(long[] sArr, int left, int right) {
            if (left + 1 < right) {
                var mid = (left + right) / 2;
                sArr = Sort(sArr, left, mid);
                sArr = Sort(sArr, mid, right);
                sArr = Merge(sArr, left, mid, right);
            }
            return sArr;
        }
    }

    static class QuickSort {
        internal static void Sort(int[] ts) {
            Sort(ts, 0, ts.Count() - 1);
        }
        /// <summary>Quickソート</summary>
        private static void Sort(int[] ts, int p, int r) {
            if (p < r) {
                var q = Partition(ts, p, r);
                Sort(ts, p, q - 1);
                Sort(ts, q + 1, r);
            }
        }

        public static int Partition(int[] sArr, int p, int r) {
            var x = sArr[r];
            var i = p - 1;
            for (int j = p; j < r; j++) {
                if (sArr[j] <= x) {
                    i++;
                    sArr.Swap(i, j);
                }
            }
            sArr.Swap(i + 1, r);
            return i + 1;
        }
    }
}


/// <summary>あまりを計算するためのintのラッパー</summary>
struct ModInt {
    int Value { get; }
    int Mod { get; }

    public override string ToString() {
        return Value.ToString();
    }

    public static explicit operator ModInt(long value) {
        return new ModInt(value);
    }

    public ModInt(long value, int mod = 1000000007) {
        this.Value = (int)(value % mod);
        this.Mod = mod;
    }

    public static explicit operator int(ModInt modInt) {
        return modInt.Value;
    }

    private static void CheckNotEqualMod(ModInt item1, ModInt item2) {
        if (item1.Mod != item2.Mod) {
            throw new Exception("mod not equal");
        }
    }

    public static ModInt operator +(ModInt item1, ModInt item2) {
        CheckNotEqualMod(item1, item2);
        long value = item1.Value + item2.Value;
        return new ModInt(value, item1.Mod);
    }

    public static ModInt operator *(ModInt item1, ModInt item2) {
        CheckNotEqualMod(item1, item2);
        long value = Math.BigMul(item1.Value, item2.Value);
        return new ModInt(value, item1.Mod);
    }

    public static ModInt operator -(ModInt item1, ModInt item2) {
        CheckNotEqualMod(item1, item2);
        long value = item1.Value - item2.Value;
        if (value < 0) {
            value += item1.Mod;
        }
        return new ModInt(value, item1.Mod);
    }

    public static ModInt operator +(ModInt item1, int item2) {
        return item1 + new ModInt(item2, item1.Mod);
    }

    public static ModInt operator *(ModInt item1, int item2) {
        return item1 * new ModInt(item2, item1.Mod);
    }

    public static ModInt operator -(ModInt item1, int item2) {
        return item1 - new ModInt(item2, item1.Mod);
    }


    public override int GetHashCode() {
        return this.Value;
    }

    public override bool Equals(object obj) {
        if (obj == null || this.GetType() != obj.GetType()) {
            return false;
        }

        var modIntObj = (ModInt)obj;
        return modIntObj.Value == this.Value;
    }

    public static bool operator ==(ModInt item1, ModInt item2) {
        return item1.Value == item2.Value;
    }

    public static bool operator !=(ModInt item1, ModInt item2) {
        return !(item1 == item2);
    }

    public static bool operator ==(ModInt item1, int item2) {
        return item1.Value == item2;
    }

    public static bool operator !=(ModInt item1, int item2) {
        return !(item1.Value == item2);
    }

    public static bool operator >=(ModInt item1, ModInt item2) {
        return item1.Value >= item2.Value;
    }

    public static bool operator <=(ModInt item1, ModInt item2) {
        return item1.Value <= item2.Value;
    }

    public static bool operator >=(ModInt item1, int item2) {
        return item1.Value >= item2;
    }

    public static bool operator <=(ModInt item1, int item2) {
        return item1.Value <= item2;
    }

    public static bool operator >(ModInt item1, ModInt item2) {
        return item1.Value > item2.Value;
    }

    public static bool operator <(ModInt item1, ModInt item2) {
        return item1.Value < item2.Value;
    }

    public static bool operator >(ModInt item1, int item2) {
        return item1.Value >= item2;
    }

    public static bool operator <(ModInt item1, int item2) {
        return item1.Value <= item2;
    }
}

/// <summary>組み合わせ</summary>
class ModCombination {
    private int mod;
    private int[] fac;
    private int[] finv;
    private int[] inv;

    public ModCombination(int max, int mod = 1000000007) {
        this.mod = mod;
        fac = new int[max]; // modが法のn!の列

        inv = new int[max]; // indexの逆元の列
        finv = new int[max]; // modを法とした、invの累積の累積

        fac[0] = 1; fac[1] = 1;
        finv[0] = 1; finv[1] = 1;
        inv[1] = 1;

        for (int i = 2; i < max; i++) {
            fac[i] = (int)(Math.BigMul(fac[i - 1], i) % mod);  // factorを求める
            var s = Math.BigMul(inv[mod % i], mod / i) % mod;
            inv[i] = (int)(mod - s);　 // iに対する逆元を求める
            finv[i] = (int)(Math.BigMul(finv[i - 1], inv[i]) % mod);
        }
    }
    /// <summary>nCk</summary>
    public int Calculation(int n, int k) {
        if (n < k) return 0;
        if (n < 0 || k < 0) return 0;

        return (int)(Math.BigMul(fac[n], (int)(Math.BigMul(finv[k], finv[n - k]) % mod)) % mod);
    }
}

/// <summary>拡張メソッドs</summary>
static class Extention {
    /// <summary>iとjを入れ替える</summary>
    public static void Swap<T>(this T[] arr, int i, int j) {
        var buf = arr[i];
        arr[i] = arr[j];
        arr[j] = buf;
    }

    /// <summary>
    /// partition。末尾sArr[r]を基準として、左に基準より小さい数、右に基準より大きい数が存在するように配列を並び替える。
    /// </summary>
    /// <param name="sArr"></param>
    /// <param name="p">partitionの先頭の添字</param>
    /// <param name="r">partitionの末尾の添字</param>
    /// <returns>partitionの基準が存在する添字</returns>
    public static int Partition(this int[] sArr, int p, int r) {
        var x = sArr[r];
        var i = p - 1;
        for (int j = p; j < r; j++) {
            if (sArr[j] <= x) {
                i++;
                sArr.Swap(i, j);
            }
        }
        sArr.Swap(i + 1, r);
        return i + 1;
    }

    /// <summary>深いコピーをする</summary>
    public static T DeepCopy<T>(this T obj) {
        T result;
        var b = new BinaryFormatter();
        using (var mem = new MemoryStream()) {
            b.Serialize(mem, obj); //  binaryFormatterによりobjをmemにserial化して書き出す
            mem.Position = 0; // memのpotisionを先頭に戻す
            result = (T)b.Deserialize(mem); // memの内容を読み取る。
        }
        return result;
    }

    public static string Left(this string str, int length) {
        return str.Substring(0, length);
    }

    public static string Right(this string str, int length) {
        return str.Substring(str.Length - length, length);
    }

    public static int Find<T>(this T[] array, T obj) {
        return Array.IndexOf(array, obj);
    }

    public static int LastFind<T>(this T[] array, T obj) {
        return Array.LastIndexOf(array, obj);
    }
}