Problem: 2050E - Three Strings
Language: java

Solution 1 (runtime: 187 ms):
import java.util.*;

import java.io.*;

import java.math.*;

import static java.lang.Math.*;



public class Main {

    static Reader sc = new Reader();

    static PrintWriter out = new PrintWriter(System.out);

    static Debug dbg = new Debug();

    static int mod = (int) (1000000007); //998244353 1000000007;

    static long hash_mod = 92233720368547753L;

    static ArrayList<ArrayList<Integer>> adj;

    static int subtree[];

    static long pref[];





    /***Code Starts From Here***/

    public static void main(String[] args) throws IOException {

        READING(); /*→→→[■□□□□□□□□□] →→→ [■■■■□□□□□□] →→→  [■■■■■■■□□□] →→→ [■■■■■■■■■□]*/ ERROR();

        //preprocess();

        // int t = 1;

        int t = sc.nextInt();

        while (t-->0) sudo_su();

        sc.close();

        out.flush();

    }



    public static void sudo_su() throws IOException {

        String a = sc.next(), b = sc.next(), c = sc.next();

        int dp[][] = new int[a.length() + 1][b.length() + 1];

        for (int current[] : dp) Arrays.fill(current, -1);

        int res = solve(0, 0, a, b, c, dp);

        out.println(res);

    }

    static int solve(int i, int j, String a, String b, String c, int dp[][]) {

        if (i >= a.length() && j >= b.length()) return 0;

        if ( (i >= a.length() && j < b.length() ) || (j >= b.length() && i < a.length())) {

            if (i >= a.length()) {

                int add = 0;

                if (c.charAt(i + j) != b.charAt(j)) add++;

                return dp[i][j] = add + solve(i, j + 1, a, b, c, dp);

            }

            else if (j >= b.length()) {

                int add = 0;

                if (c.charAt(i + j) != a.charAt(i)) add++;

                return dp[i][j] = add + solve(i + 1, j, a, b, c, dp);

            }

        }

        if (dp[i][j] != -1) return dp[i][j];

        int op1 = Integer.MAX_VALUE / 10, op2 = Integer.MAX_VALUE / 10;

        int add = 0;

        if (c.charAt(i + j) != a.charAt(i)) add++;

        op1 = add + solve(i + 1, j, a, b, c, dp);



        add = 0;

        if (c.charAt(i + j) != b.charAt(j)) add++;

        op2 = add + solve(i, j + 1, a, b, c, dp);

        return dp[i][j] = min(op1, op2);

    }





    /**Code Ends Here (No Need To Scroll Down)**/

    static class Reader {

        final private int BUFFER_SIZE = 1 << 16;

        private DataInputStream din;

        BufferedReader reader;

        private byte[] buffer;

        private int bufferPointer, bytesRead;

        public Reader() {

            din = new DataInputStream(System.in);

            buffer = new byte[BUFFER_SIZE];

            bufferPointer = bytesRead = 0;

        }

        public Reader(String file_name) throws IOException {

            din = new DataInputStream(new FileInputStream(file_name));

            buffer = new byte[BUFFER_SIZE];

            bufferPointer = bytesRead = 0;

        }

        public String readLine() throws IOException {

            byte[] buf = new byte[64];

            int cnt = 0, c;

            while ((c = read()) != -1) {

                if (c == '\n') break;

                buf[cnt++] = (byte) c;

            }

            return new String(buf, 0, cnt);

        }

        public int nextInt() throws IOException {

            int ret = 0;

            byte c = read();

            while (c <= ' ') c = read();

            boolean neg = (c == '-');

            if (neg) c = read();

            do {ret = ret * 10 + c - '0';}

            while ((c = read()) >= '0' && c <= '9');

            if (neg) return -ret;

            return ret;

        }

        public long nextLong() throws IOException {

            long ret = 0;

            byte c = read();

            while (c <= ' ') c = read();

            boolean neg = (c == '-');

            if (neg) c = read();

            do {ret = ret * 10L + c - '0';}

            while ((c = read()) >= '0' && c <= '9');

            if (neg) return -ret;

            return ret;

        }

        public double nextDouble() throws IOException {

            double ret = 0, div = 1;

            byte c = read();

            while (c <= ' ') c = read();

            boolean neg = (c == '-');

            if (neg) c = read();

            do {ret = ret * 10 + c - '0';}

            while ((c = read()) >= '0' && c <= '9');

            if (c == '.') while ((c = read()) >= '0' && c <= '9') ret += (c - '0') / (div *= 10);

            if (neg) return -ret;

            return ret;

        }

        private void fillBuffer() throws IOException {

            bytesRead = din.read(buffer, bufferPointer = 0, BUFFER_SIZE);

            if (bytesRead == -1) buffer[0] = -1;

        }

        private byte read() throws IOException {

            if (bufferPointer == bytesRead) fillBuffer();

            return buffer[bufferPointer++];

        }

        public String next() throws IOException {

            StringBuilder sb = new StringBuilder();

            byte c;

            while ((c = read()) <= ' ') ;

            do {sb.append((char) c);}

            while ((c = read()) > ' ');

            return sb.toString();

        }

        public int nextInt2() throws IOException {

            int ret = 0;

            byte c = read();

            while (c <= ' ') c = read();

            boolean neg = (c == '-');

            if (neg) c = read();

            do {ret = ret * 10 + c - '0';}

            while ((c = read()) >= '0' && c <= '9');

            if (neg) return -ret;

            return ret;

        }

        public void close() throws IOException {

            if (din == null) return;

            din.close();

        }

    }



    static long fast_pow(long a, long p, long mod) {

        long res = 1;

        while (p > 0) {

            if (p % 2 == 0) {

                a = ((a % mod) * (a % mod)) % mod;

                p /= 2;

            }

            else {

                res = ((res % mod) * (a % mod)) % mod;

                p--;

            }

        }

        return res;

    }

    static long exp(long base, long exp) {

        if (exp == 0) return 1;

        long half = exp(base, exp / 2);

        if (exp % 2 == 0) return mul(half, half);

        return mul(half, mul(half, base));

    }



    //Factorials and Inverse Factorials;

    static long[] factorials = new long[2_000_001];

    static long[] invFactorials = new long[2_000_001];

    static boolean[] isPrime;

    static int[] smallestFactorOf;

    static void precompFacts() {

        factorials[0] = invFactorials[0] = 1;

        for (int i = 1; i < factorials.length; i++)

            factorials[i] = mul(factorials[i - 1], i);

        invFactorials[factorials.length - 1] = exp(factorials[factorials.length - 1], mod - 2);

        for (int i = invFactorials.length - 2; i >= 0; i--)

            invFactorials[i] = mul(invFactorials[i + 1], i + 1);

    }

    static long nCk(int n, int k) {

        //use precompFacts first;

        return mul(factorials[n], mul(invFactorials[k], invFactorials[n - k]));

    }



    //Prime Generator;

    static void Generate_Primes(int upto) {

        // Sieve of Eratosthenes:

        isPrime = new boolean[upto + 1];

        smallestFactorOf = new int[upto + 1];

        Arrays.fill(smallestFactorOf, 1);

        Arrays.fill(isPrime, true);

        isPrime[1] = isPrime[0] = false;

        for (long i = 2; i < upto + 1; i++) {

            if (isPrime[(int) i]) {

                smallestFactorOf[(int) i] = (int) i;

                // Mark all the muresiples greater than or equal

                // to the square of i to be false.

                for (long j = i; j * i < upto + 1; j++) {

                    if (isPrime[(int) j * (int) i]) {

                        isPrime[(int) j * (int) i] = false;

                        smallestFactorOf[(int) j * (int) i] = (int) i;

                    }

                }

            }

        }

    }



    static long Div(long x, long y) {return mul(x, modinv(y));}

    static long LCM(long a, long b) {return (a / GCD(a, b)) * b;}

    static long modinv(long x) {return fast_pow(x, mod - 2, mod);}

    static long add(long a, long b) {a += b; if (a >= mod) a-= mod; return a;}

    static long mod(long a, long b) {long r = a % b;return r < 0 ? r + b : r;}    

    static long GCD(long x, long y) {if(y == 0) return x;return GCD(y, x % y);}

    static long sub(long x, long y) {long z = x - y; if (z < 0)  z += mod;return z;}

    static long mul(long a, long b) {return (long) ((long) ((a % mod) * 1L * (b % mod)) % mod);}

    public static void READING(){if(System.getProperty("ONLINE_JUDGE") == null){try{sc = new Reader("input.txt");out = new PrintWriter("output.txt");}catch (Exception e){}}}

    public static void ERROR() {try {PrintStream fileOut = new PrintStream(new FileOutputStream("dbg.txt", false), true, "UTF-8");System.setErr(fileOut);} catch (FileNotFoundException | UnsupportedEncodingException e) {e.printStackTrace();}}



    public static void sort(int[] arr) {

        //because Arrays.sort() uses quicksort which is dumb

        //Collections.sort() uses merge sort

        ArrayList<Integer> ls = new ArrayList<>();

        for (Integer x : arr) ls.add(x);

        Collections.sort(ls);

        for (int i = 0; i < arr.length; i++) arr[i] = ls.get(i);

    }



    public static void sort(long[] arr) {

        //because Arrays.sort() uses quicksort which is dumb

        //Collections.sort() uses merge sort

        ArrayList<Long> ls = new ArrayList<>();

        for (Long x : arr) ls.add(x);

        Collections.sort(ls);

        for (int i = 0; i < arr.length; i++) arr[i] = ls.get(i);

    }



    static class Unique_Pair {

        int first;

        int second;

        Unique_Pair(int first, int second) {

            this.first = first;

            this.second = second;

        }

        @Override

        public boolean equals(Object o) {

            if (this == o) return true;

            if (o == null || getClass() != o.getClass()) return false;

            Unique_Pair current = (Unique_Pair) (o);

            return first == current.first && second == current.second;

        }

        @Override

        public int hashCode() {

            return Objects.hash(first, second);

        }

        @Override

        public String toString() {

            return "(" + first + " " + second + ")";

        }

    }

    

    @SuppressWarnings("serial")

    static class CountMap<T> extends TreeMap<T, Integer>{

        CountMap() {}

        CountMap(T[] arr) {this.putCM(arr);}

        public Integer putCM(T key) {

            if (super.containsKey(key)) return super.put(key, super.get(key) + 1);

            else return super.put(key, 1);

        }

        public Integer removeCM(T key) {

            Integer count = super.get(key);

            if (count == null) return -1;

            if (count == 1) return super.remove(key);

            else  return super.put(key, super.get(key) - 1);

        }

        public Integer getCM(T key) {

            Integer count = super.get(key);

            if (count == null) return 0;

            return count;

        }

        public void putCM(T[] arr) {

            for (T ele : arr) this.putCM(ele);

        }

    }



    static class DSU {

        int[] Parent, Group_Size;

        int Number_of_Nodes, Number_of_Groups, Max_Group;

        public DSU(int Number_of_Nodes) {

            this.Number_of_Nodes = Number_of_Nodes;

            Parent = new int[Number_of_Nodes + 1];

            Group_Size = new int[Number_of_Nodes + 1];

            Number_of_Groups = Number_of_Nodes;

            Max_Group = 1;

            for (int i = 1; i <= Number_of_Nodes; i++) {

                Parent[i] = i;

                Group_Size[i] = 1;

            }

        }

        public int Leader(int x) {

            return Parent[x] = (Parent[x] == x ? x : Leader(Parent[x]));

        }

        public boolean Is_same_Group(int x, int y) {

            return Leader(x) == Leader(y);

        }

        public void unite(int x, int y) {

            int leader1 = Leader(x);

            int leader2 = Leader(y);

            if (leader1 != leader2) {

                Number_of_Groups--;

                if (Group_Size[leader1] < Group_Size[leader2]) {

                    int temp = leader1;

                    leader1 = leader2;

                    leader2 = temp;

                }

                Parent[leader2] = leader1;

                Group_Size[leader1] += Group_Size[leader2];

                Max_Group = Math.max(Max_Group, Group_Size[leader1]);

            }

        }

        public int getSize(int x) {

            return Group_Size[Leader(x)];

        }

    }



    static class Hashing {

        long[] hash1, hash2;

        long[] inv1, inv2;

        int n;

        static int muresiplier = 43;

        static final Random rnd = new Random();

        static final int mod1 = BigInteger.valueOf((int) (1e9 + rnd.nextInt((int) 1e9))).nextProbablePrime().intValue();

        static final int mod2 = BigInteger.valueOf((int) (1e9 + rnd.nextInt((int) 1e9))).nextProbablePrime().intValue();

        static final int invMuresiplier1 = BigInteger.valueOf(muresiplier).modInverse(BigInteger.valueOf(mod1)).intValue();

        static final int invMuresiplier2 = BigInteger.valueOf(muresiplier).modInverse(BigInteger.valueOf(mod2)).intValue();

        public Hashing(String s) {

            n = s.length();

            hash1 = new long[n + 1]; hash2 = new long[n + 1];

            inv1 = new long[n + 1]; inv2 = new long[n + 1];

            inv1[0] = 1; inv2[0] = 1;

            long p1 = 1; long p2 = 1;

            for (int i = 0; i < n; i++) {

                hash1[i + 1] = (hash1[i] + s.charAt(i) * p1) % mod1;

                p1 = p1 * muresiplier % mod1;

                inv1[i + 1] = inv1[i] * invMuresiplier1 % mod1;

                hash2[i + 1] = (hash2[i] + s.charAt(i) * p2) % mod2;

                p2 = p2 * muresiplier % mod2;

                inv2[i + 1] = inv2[i] * invMuresiplier2 % mod2;

            }

        }

        public long getHash(int i, int len) {

            return (((hash1[i + len] - hash1[i] + mod1) * inv1[i] % mod1) << 32) + (hash2[i + len] - hash2[i] + mod2) * inv2[i] % mod2;



        }

        public long getHashbounds(int x, int y) {

            return getHash(x, y - x + 1);

        }

    }



    static class Trie {

        class Node {

            Node[] children;

            boolean isEnd;

            Node() {

                children = new Node[26];

            }

        }

        Node root;

        Trie() {

            root = new Node();

        }

        public void insert(String word) {

            Node curr = root;

            for (char ch : word.toCharArray()) {

                if (curr.children[ch - 'a'] == null) curr.children[ch - 'a'] = new Node();

                curr = curr.children[ch - 'a'];

            }

            curr.isEnd = true;

        }

        public boolean find(String word) {

            Node curr = root;

            for (char ch : word.toCharArray()) {

                if (curr.children[ch - 'a'] == null)  return false;

                curr = curr.children[ch - 'a'];

            }

            return curr.isEnd;

        }

    }

    

    static class MultiSet<T> {

        TreeMap<T, Integer> frequency;

        TreeSet<T> set;

        int size;

        public MultiSet() {

            set = new TreeSet<>();

            frequency = new TreeMap<>();

            size = 0;

        }

        public MultiSet(Comparator<T> cmp) {

            set = new TreeSet<>(cmp);

            frequency = new TreeMap<>(cmp);

            size = 0;

        }

        public void add(T elem) {

            if (frequency.get(elem) == null || frequency.get(elem) == 0) {

                frequency.put(elem, 0);

                set.add(elem);

            }

            frequency.put(elem, frequency.get(elem) + 1);

            size++;

        }

        public void remove(T elem) {

            if (!set.contains(elem)) return;

            frequency.put(elem, frequency.get(elem) - 1);

            if (frequency.get(elem) == 0) {

                set.remove(elem);

                frequency.remove(elem);

            }

            size--;

        }

        public boolean contains(T elem) {

            return set.contains(elem);

        }

        @Override

        public String toString() {

            String current = "(";

            for (T ele : set) {

                int freq = frequency.get(ele);

                for (int i = 0; i < freq; i++) {

                    if (current.length() == 1) current += ele;

                    else current += "," + ele;

                }

            }

            current += ")";

            return current;

        }

        public int count(T element) {return frequency.getOrDefault(element, 0);}

        public int size() {int size = 0; for(int count : frequency.values()) size += count; return size;}

        public T ceiling(T element) {return frequency.ceilingKey(element);}

        public T floor(T element) {return frequency.floorKey(element);}

        public T higher(T element) {return frequency.higherKey(element);}

        public T lower(T element) { return frequency.lowerKey(element);}

        public T last() {

            return set.last();

        }

    }



    static class MultiTreeSet<E> { 

        TreeMap<E, Integer> freqTreeMap = new TreeMap<E, Integer>();

        int size;

        public MultiTreeSet() {}

        public MultiTreeSet(Collection<? extends E> c) {

            for (E element : c) add(element);

        }

        public int size() {return size;}

        public void add(E element) {

            Integer freq = freqTreeMap.get(element);

            if(freq==null) freqTreeMap.put(element, 1);

            else freqTreeMap.put(element,freq + 1);

            ++size;

        }

        public void remove(E element) {

            Integer freq = freqTreeMap.get(element);

            if(freq!=null) {

                if(freq == 1) freqTreeMap.remove(element);

                else freqTreeMap.put(element, freq-1);--size;

            }

        }

        public int get(E element) {

            Integer freq = freqTreeMap.get(element);

            if(freq == null) return 0;

            return freq;

        }

        public boolean contains(E element) {return get(element) > 0;}

        @Override 

        public String toString() {

            String current = "( ";

            for (E ele : freqTreeMap.keySet()) {

                int freq = freqTreeMap.get(ele);

                for (int i = 0; i < freq; i++) {

                    current += ele + " ";

                }

            }

            current += ")";

            return current;

        }

        public boolean isEmpty() {return size == 0;}

        public E first() {return freqTreeMap.firstKey();}

        public E last() {return freqTreeMap.lastKey();}

        public E ceiling(E element) {return freqTreeMap.ceilingKey(element);}

        public E floor(E element) {return freqTreeMap.floorKey(element);}

        public E higher(E element) {return freqTreeMap.higherKey(element);}

        public E lower(E element) {return freqTreeMap.lowerKey(element);}

    }

    

    static class Debug {

        public static boolean LOCAL = getLocal();

        public static boolean getLocal() {

            try {

                return System.getProperty("LOCAL") == null;

            }catch(SecurityException e) {

                return false;

            }

        }

        public static <T> String ts(T t) {

            if(t==null) {

                return "null";

            }

            if(t instanceof Iterable) {

                return ts((Iterable<?>) t);

            }else if(t instanceof int[]) {

                String s = Arrays.toString((int[]) t);

                return "{"+s.substring(1, s.length()-1)+"}";

            }else if(t instanceof long[]) {

                String s = Arrays.toString((long[]) t);

                return "{"+s.substring(1, s.length()-1)+"}";

            }else if(t instanceof char[]) {

                String s = Arrays.toString((char[]) t);

                return "{"+s.substring(1, s.length()-1)+"}";

            }else if(t instanceof double[]) {

                String s = Arrays.toString((double[]) t);

                return "{"+s.substring(1, s.length()-1)+"}";

            }else if(t instanceof boolean[]) {

                String s = Arrays.toString((boolean[]) t);

                return "{"+s.substring(1, s.length()-1)+"}";

            }else if(t instanceof Object[]) {

                return ts((Object[]) t);

            }

            return t.toString();

        }

        private static <T> String ts(T[] arr) {

            StringBuilder ret = new StringBuilder();

            ret.append("{");

            boolean first = true;

            for(T t: arr) {

                if(!first) ret.append(", ");

                first = false;

                ret.append(ts(t));

            }

            ret.append("}");

            return ret.toString();

        }

        private static <T> String ts(Iterable<T> iter) {

            StringBuilder ret = new StringBuilder();

            ret.append("{");

            boolean first = true;

            for(T t: iter) {

                if(!first) ret.append(", ");

                first = false;

                ret.append(ts(t));

            }

            ret.append("}");

            return ret.toString();

        }

        public static void print(Object... o) {

            if(LOCAL) {

                System.err.print("Line #"+Thread.currentThread().getStackTrace()[2].getLineNumber()+": [");

                for(int i = 0; i<o.length; i++) {

                    if(i!=0) System.err.print(", ");

                    System.err.print(ts(o[i]));

                }

                System.err.println("]");

            }

        }

    }

}

Solution 2 (runtime: 202 ms):
import java.io.BufferedReader;

import java.io.IOException;

import java.io.InputStreamReader;

import java.io.PrintStream;

import java.util.*;



public class Main {



    static int mod = 998__244______________________________________________________353;



    static int inf = (int) 2e9;



    static long infL = (long) 9e18;

    private static final int N = (int) (2e5+10);

    static int []f = new int[N];

    static int []las = new int[N];

    static int []pre = new int[N];



    static int []log = new int[N];





    static Pair<Integer,Integer> []pair = new Pair[N];

    static int n,k;



    static int[] dx = new int[]{-1,1,0,0};

    static int[] dy = new int[]{0,0,-1,1};

    static int [][] dp = new int[2025][2025];

    private static void solve(){

        String a = inStr(),b = inStr(),c = inStr();

        dp[0][0] = 0;

        for(int i=0;i<=a.length();i++){

            for(int j=0;j<=b.length();j++){

                int res = inf;

                if(i + j ==0)continue;

                if(i != 0){

                    res = Math.min(res,dp[i-1][j] + (a.charAt(i-1) == c.charAt(i + j-1)? 0 : 1));//决策a[i-1] 这个位置

                }

                if(j != 0){

                    res = Math.min(res,dp[i][j-1] + (b.charAt(j-1) == c.charAt(i + j-1)? 0 : 1));

                }

                dp[i][j] = res;

            }

        }

        println(dp[a.length()][b.length()]);

    }





    public static void main(String[] args) {

        for(int i=2;i<N;i++){

            log[i] = log[i/2] + 1;

        }

        int t = 1;

        t = in();

        while (t-- > 0) {

            solve();

        }

    }





    private static class GcdST{



        private static final int[][] st = new int[35][200020];





        public void init(int[] f,int n){

//            for(int k=0;k<=log[n]+1;k++){

//                for(int i=1;i + (1<<k) - 1 <=n ;i++){

//                    if(k==0)st[i][k] = f[i];

//                    else {

//                        st[i][k] = gcd(st[i][k-1],st[i+(1<<(k-1))][k-1]);

//                    }

//                }

//            }

            for(int k=0;k<=log[n]+1;k++){

                for(int i=1;i + (1<<k) - 1 <=n ;i++){

                    if(k==0)st[k][i] = f[i];

                    else {

                        st[k][i] = gcd(st[k-1][i],st[k-1][i+(1<<(k-1))]);

                    }

                }

            }



        }



        public int get(int l,int r){

            if(l==r){

                return st[0][l];

            }

            int x = r - l + 1;

            int res = gcd(st[log[x]][l],st[log[x]][r - (1<<log[x]) + 1]);

//            int res = 0,c = 0,base = 1;

//            while(x > 0){

//                if((x & 1) == 1){

//                    res = gcd(res,st[l][c]);

//                    l += base; // x x x x

//                }

//                x /= 2;

//                c++;

//                base *= 2;

//            }

//            for (int k = 25;k>=0;k--){

//                if(((x >> k) & 1) == 1){

//                    res = gcd(res,st[l][k]);

//                    l += 1<<k; // x x x x

//                }

//            }

            return res;

        }







    }





    private static class SegTree{



        private static class Node{

            int l,r;

            long max,min;

        }

        final Node []tr;

        public SegTree(int n){

            tr = new Node[n << 2];

            for (int i = 0; i < tr.length; i++) {

                tr[i] = new Node(); // 初始化所有节点

            }

        }

        public void init(int idx,int l,int r){

            tr[idx].l = l;

            tr[idx].r = r;

            if (l == r) { // 叶节点

                tr[idx].max = -inf;

                tr[idx].min = inf;

                return;

            }

            int mid = (l + r) >> 1;

            init(idx * 2, l, mid ); // 左子树

            init(idx * 2 + 1, mid + 1, r); // 右子树

            pushUp(idx); // 合并子树信息

        }

        // 合并子节点信息

        private void pushUp(int idx) {

            tr[idx].max = Math.max(tr[idx * 2].max, tr[idx * 2 + 1].max);

            tr[idx].min = Math.min(tr[idx * 2].min, tr[idx * 2 + 1].min);

        }





        // 区间查询最大值和最小值

        public long[] query(int l, int r, int idx) {

            if (tr[idx].l >= l && tr[idx].r <= r) { // 当前节点区间完全包含在查询区间中

                return new long[]{tr[idx].max, tr[idx].min};

            }

            int mid = (tr[idx].l + tr[idx].r) >> 1;

            long maxVal = Long.MIN_VALUE;

            long minVal = Long.MAX_VALUE;

            if (l <= mid) { // 查询左子树

                long[] leftRes = query(l, r, idx * 2);

                maxVal = leftRes[0];

                minVal = leftRes[1];

            }

            if (r > mid) { // 查询右子树

                long[] rightRes = query(l, r, idx * 2 + 1);

                maxVal = Math.max(maxVal, rightRes[0]);

                minVal = Math.min(minVal, rightRes[1]);

            }

            return new long[]{maxVal, minVal};

        }



        // 单点更新

        public void update(int idx, int pos, int value) {

            if (tr[idx].l == tr[idx].r) { // 找到目标叶节点

                tr[idx].max = tr[idx].min = value;

                return;

            }

            int mid = (tr[idx].l + tr[idx].r) >> 1;

            if (pos <= mid) { // 更新左子树

                update(idx * 2,pos, value);

            } else { // 更新右子树

                update(idx * 2 + 1,pos, value);

            }

            pushUp(idx); // 更新当前节点

        }



    }



    //  -===-      MATH       -===-  //



    static int fact(int n) {

        int r = 1;

        for (int i = 1; i <= n; i++) {

            r = (int) (((long) r * i) % mod);

        }

        return r;

    }



    static int C(int n, int k) {

        return (int) (((((long) fact(n) * pow(fact(k), mod - 2)) % mod) * pow(fact(n - k), mod - 2)) % mod);

    }



    static int gcd(int i1, int i2) {

        if (i2 == 0) return i1;

        return gcd(i2, i1 % i2);

    }



    static long gcd(long i1, long i2) {

        if (i2 == 0) return i1;

        return gcd(i2, i1 % i2);

    }



    static int pow(int x, int y) {

        x = x % mod;

        if (x == 0) return 0;

        int r = 1;

        while (y > 0) {

            if ((y & 1) != 0) r = (int) (((long) r * x) % mod);

            y /= 2;

            x = (int) (((long) x * x) % mod);

        }

        return r % mod;

    }



    static void swap(int[] a, int i, int j) {

        int tmp = a[i];

        a[i] = a[j];

        a[j] = tmp;

    }



    static int digitSum(long n) {

        int r = 0;

        while (n != 0) {

            r += (int) (n % 10);

            n /= 10;

        }

        return r;

    }



    //  -===- DATA STRUCTURES -===-  //



    static class UnionFind {



        int[] p, rank, min, max, sz;

        int n, c;



        UnionFind(int n) {

            this.n = n;

            p = new int[n];

            rank = new int[n];

            min = new int[n];

            max = new int[n];

            sz = new int[n];

            for (int i = 0; i < p.length; i++) {

                p[i] = i;

                min[i] = i;

                max[i] = i;

                sz[i] = 1;

            }

        }



        int find(int a) {

            return p[a] = (p[a] == a ? a : find(p[a]));

        }



        void union(int a, int b) {

            a = find(a);

            b = find(b);

            if (a == b) return;

            if (rank[a] > rank[b]) {

                p[b] = a;

                max[a] = Math.max(max[a], max[b]);

                min[a] = Math.min(min[a], min[b]);

                sz[a] += sz[b];

            } else {

                p[a] = b;

                max[b] = Math.max(max[b], max[a]);

                min[b] = Math.min(min[b], min[a]);

                sz[b] += sz[a];

                if (rank[a] == rank[b]) {

                    rank[b]++;

                }

            }

            c--;

        }

    }



    private static class Pair<F, S> {



        int index;



        F first;

        S second;



        public Pair(F f, S s) {

            this.first = f;

            this.second = s;

        }



        public F getFirst() {

            return first;

        }



        public S getSecond() {

            return second;

        }



        public void setFirst(F first) {

            this.first = first;

        }



        public void setSecond(S second) {

            this.second = second;

        }



        public int getIndex() {

            return index;

        }



        public void setIndex(Integer index) {

            this.index = index;

        }



        @Override

        public String toString(){

            return first.toString() + ',' + second.toString();

        }



    }





    //  -===-      IN      -===-  //

    static StringTokenizer STT;



    static BufferedReader br = new BufferedReader(new InputStreamReader(System.in));



    static PrintStream out = System.out;



    static String inStr() {

        while (STT == null || !STT.hasMoreElements()) {

            try {

                STT = new StringTokenizer(br.readLine());

            } catch (IOException e) {

                throw new RuntimeException(e);

            }

        }

        return STT.nextToken();

    }



    static int in() {

        return Integer.parseInt(inStr());

    }



    static long inLong() {

        return Long.parseLong(inStr());

    }



    static double inDouble() {

        return Double.parseDouble(inStr());

    }



    static String inLine() {

        String s;

        try {

            if (STT != null && STT.hasMoreTokens()) {

                s = STT.nextToken("\n");

            } else {

                s = br.readLine();

            }

        } catch (IOException e) {

            throw new RuntimeException(e);

        }

        return s;

    }



    static long[] inArrLong() {

        String[] split = inLine().split(" ");

        long[] a = new long[split.length];

        for (int i = 0; i < a.length; i++) {

            a[i] = Long.parseLong(split[i]);

        }

        return a;

    }



    static int[] inArr() {

        String s = inLine();

        String[] split = s.split(" ");

        int[] a = new int[split.length];

        for (int i = 0; i < a.length; i++) {

            a[i] = Integer.parseInt(split[i]);

        }

        return a;

    }



    //  -===-      PRINT      -===-  //



    static void YES() {

        out.println("YES");

    }



    static void NO() {

        out.println("NO");

    }



    static void println() {

        out.println();

    }



    static void println(int a) {

        out.println(a);

    }



    static void print(int a) {

        out.print(a);

    }



    static void println(long a) {

        out.println(a);

    }



    static void print(long a) {

        out.print(a);

    }



    static void println(double a) {

        out.println(a);

    }



    static void print(double a) {

        out.print(a);

    }



    static void println(String a) {

        out.println(a);

    }



    static void print(String a) {

        out.print(a);

    }



    static void print(int[] a) {

        for (int i = 0; i < a.length - 1; i++) {

            out.print(a[i] + " ");

        }

        if (a.length > 0) {

            out.println(a[a.length - 1]);

        }

    }



    static void print(List<?> l) {

        for (int i = 0; i < l.size() - 1; i++) {

            out.print(l.get(i) + " ");

        }

        if (!l.isEmpty()) {

            out.println(l.get(l.size() - 1));

        }

    }





    public static class D {

        private final int[] dArray; // 离散化后的数组



        public int index;



        // 初始化方法

        public D(int[] oArray,int n) {

            // 1. 去重

            Set<Integer> set = new HashSet<>();

            for(int i=1;i<=n;i++){

                set.add(oArray[i]);

            }



            // 2. 转换为数组并排序

            dArray = new int[set.size()+1];

            index = 0;

            for (int num : set) {

                dArray[++index] = num;

            }

            Arrays.sort(dArray,1,index+1);

        }



        public int getOld(int x){

            return dArray[x];

        }



        // 获取离散化后的值（二分查找实现）

        public int get(int target) {

            int left = 1;

            int right = index;



            while (left <= right) {

                int mid = left + (right - left) / 2;

                if (dArray[mid] == target) {

                    return mid; // 返回下标 + 1（假设下标从 1 开始）

                } else if (dArray[mid] < target) {

                    left = mid + 1;

                } else {

                    right = mid - 1;

                }

            }



            return -1; // 如果未找到，返回 -1

        }



    }



}