using System.Diagnostics; using System.Reflection.Emit; using System.Runtime.InteropServices.Marshalling; using System.Security.Cryptography; using System.Security.Cryptography.X509Certificates; using Microsoft.VisualBasic; namespace test { internal class Program { static void Main(string[] args) { cin = new input(); mod = new mod(998244353); toolbox = new toolbox(); Priority_Queue = new Priority_Queue(true); var sw = new System.IO.StreamWriter(Console.OpenStandardOutput()) { AutoFlush = false }; Console.SetOut(sw); toolbox.StartTimer(); int n = cin.intreed(); int q = cin.intreed(); var arr = new List();//1indexにしておく arr.Add(0); for (int i = 1; i <= n; i++) { arr.Add(cin.longreed()); } var tree = new AvlMultiset(); bool sorted = false;//1度でもソートされたか var changed = new Dictionary(); for (int i = 1; i <= n; i++) changed[i]=arr[i]; while (q-- > 0) { int mode = cin.intreed(); if (mode == 1) { int k = cin.intreed();//k番目の値が更新される long x = cin.longreed(); changed[k]=x; } else if (mode == 2) { var remove = new List(); if (sorted) { foreach (var k in changed) { remove.Add(tree[k.Key]);//k番目の要素は削除する } foreach (var i in remove) tree.Erase(i); } foreach (var k in changed) tree.Insert(k.Value); changed.Clear(); sorted = true; } else { int k = cin.intreed(); if (changed.ContainsKey(k)) { System.Console.WriteLine(changed[k]); } else { System.Console.WriteLine(tree[k]); } } } toolbox.PrintElapsedTime(); Console.Out.Flush(); } static input cin; static mod mod; static toolbox toolbox; static Priority_Queue Priority_Queue; } public class AvlMultiset { //1-indexです!!!!!! private class node { public long val; public int cnt;//同じ値の個数 public int height; public int size;//部分木内の要素数(cnt含む) public node left; public node right; public node(long v) { val = v; cnt = 1; height = 1; size = 1; } } private node root; private static int Height(node t) => t?.height ?? 0; private static int Size(node t) => t?.size ?? 0; private static void Update(node t) { if (t == null) return; t.height = Math.Max(Height(t.left), Height(t.right)) + 1; t.size = Size(t.left) + Size(t.right) + t.cnt; } private static int BalanceFactor(node t) => Height(t.left) - Height(t.right); private static node RotateRight(node y) { var x = y.left; var t2 = x.right; x.right = y; y.left = t2; Update(y); Update(x); return x; } private static node RotateLeft(node x) { var y = x.right; var t2 = y.left; y.left = x; x.right = t2; Update(x); Update(y); return y; } private static node Balance(node t) { if (t == null) return null; Update(t); int bf = BalanceFactor(t); if (bf > 1) { if (BalanceFactor(t.left) < 0) { t.left = RotateLeft(t.left); } return RotateRight(t); } if (bf < -1) { if (BalanceFactor(t.right) > 0) { t.right = RotateRight(t.right); } return RotateLeft(t); } return t; } private node Insert(node t, long val) { if (t == null) return new node(val); if (val < t.val) { t.left = Insert(t.left, val); } else if (val > t.val) { t.right = Insert(t.right, val); } else { t.cnt++; Update(t); return t; } return Balance(t); } private node RemoveMin(node t, out node removed) { if (t.left == null) { removed = t; var right = t.right; t.left = null; t.right = null; return right; } t.left = RemoveMin(t.left, out removed); return Balance(t); } private node Erase(node t, long val) { if (t == null) return null; if (val < t.val) { t.left = Erase(t.left, val); } else if (val > t.val) { t.right = Erase(t.right, val); } else { if (t.cnt > 1) { t.cnt--; return Balance(t); } if (t.left == null) return t.right; if (t.right == null) return t.left; t.right = RemoveMin(t.right, out var successor); successor.left = t.left; successor.right = t.right; t = successor; } return Balance(t); } private bool Find(node t, long val) { while (t != null) { if (val < t.val) t = t.left; else if (val > t.val) t = t.right; else return true; } return false; } private long GetKth(node t, int k) { if (t == null || k < 1 || k > Size(t)) throw new ArgumentOutOfRangeException(nameof(k)); int leftCount = Size(t.left); if (k <= leftCount) { return GetKth(t.left, k); } if (k <= leftCount + t.cnt) { return t.val; } return GetKth(t.right, k - leftCount - t.cnt); } //外部向け public void Insert(long val) => root = Insert(root, val); public void Erase(long val) => root = Erase(root, val); public bool Find(long val) => Find(root, val); public int Count() => Size(root); public long this[int index] => GetKth(root, index); } internal class UnionFind { public int[] tree { get; set; } static toolbox toolbox; public UnionFind(int s) { tree = Enumerable.Repeat(-1, s + 1).ToArray(); } public int getroot(int i) { return tree[i] < 0 ? i : tree[i] = getroot(tree[i]); } public bool groupcheck(int i, int t) { return getroot(i) == getroot(t); } public bool unite(int i, int t) { toolbox = new toolbox(); var x = getroot(i); var y = getroot(t); if (x != y) { if (tree[x] > tree[y]) { toolbox.Swap(ref x, ref y); } tree[x] += tree[y]; tree[y] = x; } return x != y; } public int get_cnt(int i) { return tree[getroot(i)] * -1; } } public static class Extensions { public static Dictionary safe_addtion_for_dictionary_int(this Dictionary dic, T key) { if (dic.ContainsKey(key)) dic[key]++; else dic.Add(key, 1); return dic; } public static Dictionary safe_addtion_for_dictionary_long(this Dictionary dic, T key) { if (dic.ContainsKey(key)) dic[key]++; else dic.Add(key, 1); return dic; } public static Dictionary> safe_addtion_for_list_in_dictionary(this Dictionary> dic, T key, T2 value) { if (dic.ContainsKey(key)) dic[key].Add(value); else dic.Add(key, new List() { value }); return dic; } public static T list_pop_back(this List a) { var k = a[a.Count - 1]; a.RemoveAt(a.Count - 1); return k; } public static T chmin(ref this T a, T b) where T : struct, IComparable { if (a.CompareTo(b) > 0) return a = b; else return a; } public static T chmax(ref this T a, T b) where T : struct, IComparable { if (a.CompareTo(b) < 0) return a = b; else return a; } } internal class input { string[] soloinput; int t; public input() { soloinput = new string[0]; t = 0; } public string soloreed() { if (t < soloinput.Length) { return soloinput[t++]; } string input = Console.ReadLine(); while (input == "") { input = Console.ReadLine(); } soloinput = input.Split(" "); t = 0; return soloinput[t++]; } public int intreed() { return int.Parse(soloreed()); } public int[] arrayint(int N) { int[] A = new int[N]; for (int i = 0; i < N; i++) { A[i] = intreed(); } return A; } public long longreed() { return long.Parse(soloreed()); } public long[] arraylong(long N) { long[] A = new long[N]; for (long i = 0; i < N; i++) { A[i] = longreed(); } return A; } public decimal decimalreed() { return decimal.Parse(soloreed()); } public decimal[] arraydecimal(long N) { decimal[] A = new decimal[N]; for (decimal i = 0; i < N; i++) { A[(long)i] = decimalreed(); } return A; } } internal class mod { public long T { get; set; } public mod(long mod = 1000000007) { T = mod; } public long addition(long A, long B) { decimal C = A + B; return (long)C % T; } public long subtraction(long A, long B) { decimal C = A - B; return C % T >= 0 ? (long)C % T : (long)(C + T) % T; } public long multiplication(long A, long B) { return ((A % T) * (B % T)) % T; } } internal class toolbox { string Y = "Yes"; string N = "No"; static input cin; private DateTime? startTime; public toolbox() { cin = new input(); } public long[] CumulativeSum(long[] A, bool mode = true) { if (mode == false) Array.Reverse(A); long[] back = new long[A.Length + 1]; back[0] = 0; for (int i = 1; i <= A.Length; i++) { back[i] = back[i - 1] + A[i - 1]; } if (mode == false) Array.Reverse(A); return back; } public long[] Eratosthenes(long A) { A++; var back = new List(); bool[] ch = new bool[A]; for (int i = 2; i < A; i++) ch[i] = true; for (long i = 2; i < Math.Sqrt(A); i++) { if (ch[i] == true) { back.Add(i); for (long t = 1; i * t < A; t++) { ch[i * t] = false; } } } for (long i = 0; i < A; i++) { if (ch[i] == true) back.Add(i); } return back.Distinct().ToArray(); } public void Swap(ref T a, ref T b) { var i = a; a = b; b = i; } public void LSwap(ref List A, int a, int b) { var i = A[a]; A[a] = A[b]; A[b] = i; } public long Gcd(long A, long B) { while (A != 0) { B %= A; Swap(ref A, ref B); } return B; } public long[] AllDivisors(long N) { var back = new List(); for (int i = 1; Math.Pow(i, 2) <= N; i++) { if (N % i == 0) { back.Add(i); back.Add(N / i); } } return back.Distinct().ToArray(); } public static IEnumerable ExhaustiveEnumeration(IEnumerable indata) { if (indata.Count() == 1) yield return new T[] { indata.First() }; foreach (var i in indata) { var used = new T[] { i }; var unused = indata.Except(used); foreach (var t in ExhaustiveEnumeration(unused)) yield return used.Concat(t).ToArray(); } //How to use //var allpattern = toolbox.ExhaustiveEnumeration(Enumerable.Range(1, N)); } public bool[,] bitallsearch(int N) { bool[,] back = new bool[(int)Math.Pow(2, N), N]; for (int i = 0; i < Math.Pow(2, N); i++) { for (int t = 0; t < N; t++) { var k = (i >> t) & 1; if (k == 1) { back[i, t] = true; } } } return back; } public static int BS(T[] A, T key) where T : IComparable { //このコード、定数倍が大変な事になってるので標準ライブラリを使いましょう(BinarySearch) int left = 0; int right = A.Length; int mid = 0; while (left < right) { mid = (left + right) / 2; if (A[mid].CompareTo(key) == 0) return mid; else if (A[mid].CompareTo(key) > 0) right = mid; else if (A[mid].CompareTo(key) < 0) left = mid + 1; } return -1; } public static int lower_bound(T[] a, T v) { return lower_bound(a, v, Comparer.Default); } public static int lower_bound(T[] A, T key, Comparer v) { int left = 0; int right = A.Length - 1; int mid = 0; var W = 0; while (left <= right) { mid = (left + right) / 2; W = v.Compare(A[mid], key); if (W == -1) left = mid + 1; else right = mid - 1; } return left; } public long[] prime_factorize(long N) { long T = N; var back = new List(); for (long i = 2; i * i <= T; i++) { if (T % i != 0) continue; while (T % i == 0) { back.Add(i); T /= i; } } if (T != 1) back.Add(T); return back.ToArray(); } public long[] One_dimensional_Coordinate_Compression(long[] A) { long[] back = new long[A.Length]; var T = A.Distinct().ToList(); T.Sort(); for (int i = 0; i < A.Length; i++) back[i] = T.BinarySearch(A[i]); return back; } public void setYN(string A = "Yes", string B = "No") { Y = A; N = B; } public void YN(bool ans) { if (ans) Console.WriteLine(Y); else Console.WriteLine(N); } public string[] x_dekakou(int H, int W) { var s = new string[H + 2]; for (int i = 0; i < W + 2; i++) { s[0] += "x"; s[H + 1] += "x"; } for (int i = 1; i < H + 1; i++) { //x場外 .白 #黒 s[i] = "x" + Console.ReadLine().Replace(" ", "") + "x"; } return s; } public List> x_dekakou_string(int H, int W) { var back = new List>(); for (int i = 0; i < H + 2; i++) back.Add(Enumerable.Repeat(-1, W + 2).ToList()); for (int i = 0; i < W + 2; i++) { back[0][i] = -1; back[H + 1][i] = -1; } for (int i = 1; i <= H; i++) { back[i][0] = -1; back[i][W + 1] = -1; for (int t = 1; t <= W; t++) back[i][t] = cin.intreed(); } return back; } /// /// 配列の指定位置以降を反転する /// /// 反転対象の配列 /// 反転開始位置(この位置以降が反転される) private void Reverse(T[] array, int begin) where T : IComparable { // 反転する要素が2個未満の場合は何もしない if (array.Length - begin < 2) return; // 両端から中央に向かって要素を交換 int left = begin; int right = array.Length - 1; while (left < right) { Swap(ref array[left], ref array[right]); left++; right--; } } /// /// 配列を辞書順で次の順列に変更する /// 全ての順列を列挙するには、事前に Array.Sort() でソートした配列を渡すこと /// /// 順列を生成する配列(事前ソート必須) /// 次の順列が存在する場合true、最大順列の場合false public bool NextPermutation(T[] array) where T : IComparable { // 辞書順で次に大きい順列を生成 // 1. 右端から降順でない位置を探す int pivotIndex = -1; for (int i = array.Length - 2; i >= 0; i--) { if (array[i].CompareTo(array[i + 1]) < 0) // 昇順ペア発見 { pivotIndex = i; break; } } // 最大順列に到達している場合 if (pivotIndex == -1) return false; // 2. pivotより大きい最右の要素と交換 for (int j = array.Length - 1; j > pivotIndex; j--) { if (array[pivotIndex].CompareTo(array[j]) < 0) { Swap(ref array[pivotIndex], ref array[j]); break; } } // 3. pivot以降を昇順に並べ直し Reverse(array, pivotIndex + 1); return true; // how to use // do{}while(NextPermutation) } /// /// 回文判定のコア処理(配列版) /// private bool IsPalindromeCore(T[] array, int left, int right) where T : IComparable { while (left < right) { if (array[left].CompareTo(array[right]) != 0) return false; left++; right--; } return true; } /// /// 回文判定のコア処理(文字列版) /// private bool IsPalindromeCore(string str, int left, int right) { while (left < right) { if (str[left] != str[right]) return false; left++; right--; } return true; } /// /// 配列全体が回文かどうかを判定 /// public bool IsPalindrome(T[] array) where T : IComparable { return IsPalindromeCore(array, 0, array.Length - 1); } /// /// 文字列全体が回文かどうかを判定 /// public bool IsPalindrome(string str) { return IsPalindromeCore(str, 0, str.Length - 1); } /// /// 指定範囲が回文かどうかを判定(配列版) /// public bool IsPalindrome(T[] array, int start, int end) where T : IComparable { return IsPalindromeCore(array, start, end); } /// /// 指定範囲が回文かどうかを判定(文字列版) /// public bool IsPalindrome(string str, int start, int end) { return IsPalindromeCore(str, start, end); } /// /// 指定長さの部分配列に回文が含まれるかを判定 /// public bool HasPalindrome(T[] array, int length) where T : IComparable { for (int i = 0; i <= array.Length - length; i++) { if (IsPalindromeCore(array, i, i + length - 1)) return true; } return false; } /// /// 指定長さの部分文字列に回文が含まれるかを判定 /// public bool HasPalindrome(string str, int length) { for (int i = 0; i <= str.Length - length; i++) { if (IsPalindromeCore(str, i, i + length - 1)) return true; } return false; } public void StartTimer() { startTime = DateTime.Now; } public void PrintElapsedTime(bool error_output = true) { //標準出力ではなくて標準エラー出力を使ってるのでatcoderのジャッジはこの出力を無視する つまり消さなくてok 便利だね if (startTime.HasValue) { var elapsed = DateTime.Now - startTime.Value; if (error_output) Console.Error.WriteLine($"Elapsed time: {elapsed.TotalMilliseconds} ms"); else Console.WriteLine($"Elapsed time: {elapsed.TotalMilliseconds} ms"); } else { Console.Error.WriteLine("Timer was not started."); } } } internal class Priority_Queue { toolbox toolbox = new toolbox(); public List<(long, long)> Queue { get; private set; } /// /// true==>大きいやつから出るよ false==>小さいやつからでるよ /// //そとからいじれるのよくないよ えびちゃんより public bool revase { get; set; } public Priority_Queue(bool cnt = true) { Queue = new List<(long, long)>(); revase = cnt; } public void Enqueue(long a, long b) { if (revase == false) a *= -1; int i = Queue.Count, t; Queue.Add((a, b)); while (i != 0) { t = (i - 1) / 2; if (Queue[i].Item1 > Queue[t].Item1) { var k = Queue[i]; Queue[i] = Queue[t]; Queue[t] = k; i = t; } else { break; } } } public (long, long) Dequeue() { int a = Queue.Count - 1; var back = Queue[0]; Queue[0] = Queue[a]; Queue.RemoveAt(a); for (int i = 0, j; (j = 2 * i + 1) < a;) { if (j != a - 1 && Queue[j].Item1 < Queue[j + 1].Item1) j++; if (Queue[i].Item1 < Queue[j].Item1) { var k = Queue[i]; Queue[i] = Queue[j]; Queue[j] = k; i = j; } else { break; } } if (revase == false) back.Item1 *= -1; return back; } } internal class Generic_Priority_Queue { toolbox toolbox = new toolbox(); public List<(long, T)> Queue { get; private set; } /// /// true==>大きいやつから出るよ false==>小さいやつからでるよ /// public bool revase { get; set; } public Generic_Priority_Queue(bool cnt = true) { Queue = new List<(long, T)>(); revase = cnt; } public void Enqueue(long a, T b) { if (revase == false) a *= -1; int i = Queue.Count, t; Queue.Add((a, b)); while (i != 0) { t = (i - 1) / 2; if (Queue[i].Item1 > Queue[t].Item1) { var k = Queue[i]; Queue[i] = Queue[t]; Queue[t] = k; i = t; } else { break; } } } public (long, T) Dequeue() { int a = Queue.Count - 1; var back = Queue[0]; Queue[0] = Queue[a]; Queue.RemoveAt(a); for (int i = 0, j; (j = 2 * i + 1) < a;) { if (j != a - 1 && Queue[j].Item1 < Queue[j + 1].Item1) j++; if (Queue[i].Item1 < Queue[j].Item1) { var k = Queue[i]; Queue[i] = Queue[j]; Queue[j] = k; i = j; } else { break; } } if (revase == false) back.Item1 *= -1; return back; } public (long, T) get_first() { if (Queue.Count == 0) return (default(long), default(T)); else return Queue[0]; } } }