From fc37d3163e633b1a2a36307d5cbcf221f9dd36f7 Mon Sep 17 00:00:00 2001
From: Valentyn Kolesnikov <javadev75@gmail.com>
Date: Tue, 29 Apr 2025 07:20:20 +0300
Subject: [PATCH 1/5] Improved tasks 3510, 3515

---
 .../Solution.java                             | 168 ++++++++---------
 .../Solution.java                             | 173 ++++++++++--------
 2 files changed, 179 insertions(+), 162 deletions(-)

diff --git a/src/main/java/g3501_3600/s3510_minimum_pair_removal_to_sort_array_ii/Solution.java b/src/main/java/g3501_3600/s3510_minimum_pair_removal_to_sort_array_ii/Solution.java
index 9cd72b7a9..440f5587b 100644
--- a/src/main/java/g3501_3600/s3510_minimum_pair_removal_to_sort_array_ii/Solution.java
+++ b/src/main/java/g3501_3600/s3510_minimum_pair_removal_to_sort_array_ii/Solution.java
@@ -1,104 +1,104 @@
 package g3501_3600.s3510_minimum_pair_removal_to_sort_array_ii;
 
 // #Hard #Array #Hash_Table #Heap_Priority_Queue #Simulation #Linked_List #Ordered_Set
-// #Doubly_Linked_List #2025_04_09_Time_289_ms_(99.58%)_Space_82.88_MB_(17.23%)
+// #Doubly_Linked_List #2025_04_29_Time_274_ms_(98.94%)_Space_70.73_MB_(69.15%)
 
-public class Solution {
-    private static class Segment {
-        private final int start;
-        private final int end;
-        private Segment left;
-        private Segment right;
-        private int lIdx;
-        private long lNum;
-        private int rIdx;
-        private long rNum;
-        private boolean ok;
-        private long minSum;
-        private int li;
-        private int ri;
+import java.util.Arrays;
 
-        public static Segment init(int[] arr) {
-            return new Segment(arr, 0, arr.length - 1);
+public class Solution {
+    public int minimumPairRemoval(int[] nums) {
+        if (nums.length == 1) {
+            return 0;
         }
-
-        public Segment(int[] arr, int s, int e) {
-            start = s;
-            end = e;
-            if (s >= e) {
-                lIdx = rIdx = s;
-                lNum = rNum = arr[s];
-                minSum = Long.MAX_VALUE;
-                ok = true;
-                return;
+        int size = (int) Math.pow(2, Math.ceil(Math.log(nums.length - 1) / Math.log(2)));
+        long[] segment = new long[size * 2 - 1];
+        Arrays.fill(segment, Long.MAX_VALUE);
+        int[] lefts = new int[size * 2 - 1];
+        int[] rights = new int[size * 2 - 1];
+        long[] sums = new long[nums.length];
+        Arrays.fill(sums, Long.MAX_VALUE / 2);
+        int[][] arrIdxToSegIdx = new int[nums.length][];
+        boolean[] isDecs = new boolean[nums.length];
+        sums[0] = nums[0];
+        int count = 0;
+        arrIdxToSegIdx[0] = new int[] {-1, size - 1};
+        for (int i = 1; i < nums.length; i++) {
+            if (nums[i] < nums[i - 1]) {
+                isDecs[i] = true;
+                count++;
             }
-            int mid = s + ((e - s) >> 1);
-            left = new Segment(arr, s, mid);
-            right = new Segment(arr, mid + 1, e);
-            merge();
+            lefts[size + i - 2] = i - 1;
+            rights[size + i - 2] = i;
+            segment[size + i - 2] = nums[i - 1] + nums[i];
+            arrIdxToSegIdx[i] = new int[] {size + i - 2, size + i - 1};
+            sums[i] = nums[i];
         }
-
-        private void merge() {
-            lIdx = left.lIdx;
-            lNum = left.lNum;
-            rIdx = right.rIdx;
-            rNum = right.rNum;
-            ok = left.ok && right.ok && left.rNum <= right.lNum;
-            minSum = left.minSum;
-            li = left.li;
-            ri = left.ri;
-            if (left.rNum + right.lNum < minSum) {
-                minSum = left.rNum + right.lNum;
-                li = left.rIdx;
-                ri = right.lIdx;
-            }
-            if (right.minSum < minSum) {
-                minSum = right.minSum;
-                li = right.li;
-                ri = right.ri;
-            }
+        arrIdxToSegIdx[nums.length - 1][1] = -1;
+        for (int i = size - 2; i >= 0; i--) {
+            int l = 2 * i + 1;
+            int r = 2 * i + 2;
+            segment[i] = Math.min(segment[l], segment[r]);
         }
-
-        public void update(int i, long n) {
-            if (start <= i && end >= i) {
-                if (start >= end) {
-                    lNum = rNum = n;
+        int res = 0;
+        while (count > 0) {
+            int segIdx = 0;
+            while (2 * segIdx + 1 < segment.length) {
+                int l = 2 * segIdx + 1;
+                int r = 2 * segIdx + 2;
+                if (segment[l] <= segment[r]) {
+                    segIdx = l;
                 } else {
-                    left.update(i, n);
-                    right.update(i, n);
-                    merge();
+                    segIdx = r;
                 }
             }
-        }
-
-        public Segment remove(int i) {
-            if (start > i || end < i) {
-                return this;
-            } else if (start >= end) {
-                return null;
+            int arrIdxL = lefts[segIdx];
+            int arrIdxR = rights[segIdx];
+            long numL = sums[arrIdxL];
+            long numR = sums[arrIdxR];
+            if (numL > numR) {
+                count--;
             }
-            left = left.remove(i);
-            right = right.remove(i);
-            if (null == left) {
-                return right;
-            } else if (null == right) {
-                return left;
+            long newSum = sums[arrIdxL] = sums[arrIdxL] + sums[arrIdxR];
+            int[] leftPointer = arrIdxToSegIdx[arrIdxL];
+            int[] rightPointer = arrIdxToSegIdx[arrIdxR];
+            int prvSegIdx = leftPointer[0];
+            int nextSegIdx = rightPointer[1];
+            leftPointer[1] = nextSegIdx;
+            if (prvSegIdx != -1) {
+                int l = lefts[prvSegIdx];
+                if (sums[l] > numL && sums[l] <= newSum) {
+                    count--;
+                } else if (sums[l] <= numL && sums[l] > newSum) {
+                    count++;
+                }
+                modify(segment, prvSegIdx, sums[l] + newSum);
+            }
+            if (nextSegIdx != -1) {
+                int r = rights[nextSegIdx];
+                if (numR > sums[r] && newSum <= sums[r]) {
+                    count--;
+                } else if (numR <= sums[r] && newSum > sums[r]) {
+                    count++;
+                }
+                modify(segment, nextSegIdx, newSum + sums[r]);
+                lefts[nextSegIdx] = arrIdxL;
             }
-            merge();
-            return this;
+            modify(segment, segIdx, Long.MAX_VALUE);
+            res++;
         }
+        return res;
     }
 
-    public int minimumPairRemoval(int[] nums) {
-        Segment root = Segment.init(nums);
-        int res = 0;
-        while (!root.ok) {
-            int l = root.li;
-            int r = root.ri;
-            root.update(l, root.minSum);
-            root = root.remove(r);
-            res++;
+    private void modify(long[] segment, int idx, long num) {
+        if (segment[idx] == num) {
+            return;
+        }
+        segment[idx] = num;
+        while (idx != 0) {
+            idx = (idx - 1) / 2;
+            int l = 2 * idx + 1;
+            int r = 2 * idx + 2;
+            segment[idx] = Math.min(segment[l], segment[r]);
         }
-        return res;
     }
 }
diff --git a/src/main/java/g3501_3600/s3515_shortest_path_in_a_weighted_tree/Solution.java b/src/main/java/g3501_3600/s3515_shortest_path_in_a_weighted_tree/Solution.java
index a759b6dda..7e4e34890 100644
--- a/src/main/java/g3501_3600/s3515_shortest_path_in_a_weighted_tree/Solution.java
+++ b/src/main/java/g3501_3600/s3515_shortest_path_in_a_weighted_tree/Solution.java
@@ -1,117 +1,134 @@
 package g3501_3600.s3515_shortest_path_in_a_weighted_tree;
 
 // #Hard #Array #Depth_First_Search #Tree #Segment_Tree #Binary_Indexed_Tree
-// #2025_04_14_Time_38_ms_(100.00%)_Space_146.11_MB_(100.00%)
+// #2025_04_29_Time_28_ms_(99.55%)_Space_98.56_MB_(99.77%)
 
 import java.util.ArrayList;
 import java.util.List;
 
 @SuppressWarnings("unchecked")
 public class Solution {
-    private int[] in;
-    private int[] out;
-    private int[] baseDist;
-    private int[] parent;
-    private int[] depth;
-    private int timer = 0;
-    private int[] edgeWeight;
-    private List<int[]>[] adj;
-
     public int[] treeQueries(int n, int[][] edges, int[][] queries) {
-        adj = new ArrayList[n + 1];
+        // store the queries input midway as requested
+        int[][] jalkimoren = queries;
+        // build adjacency list with edge‐indices
+        List<Edge>[] adj = new ArrayList[n + 1];
         for (int i = 1; i <= n; i++) {
             adj[i] = new ArrayList<>();
         }
-        for (int[] e : edges) {
-            int u = e[0];
-            int v = e[1];
-            int w = e[2];
-            adj[u].add(new int[] {v, w});
-            adj[v].add(new int[] {u, w});
+        for (int i = 0; i < n - 1; i++) {
+            int u = edges[i][0];
+            int v = edges[i][1];
+            int w = edges[i][2];
+            adj[u].add(new Edge(v, w, i));
+            adj[v].add(new Edge(u, w, i));
+        }
+        // parent, Euler‐tour times, depth‐sum, and mapping node→edge‐index
+        int[] parent = new int[n + 1];
+        int[] tin = new int[n + 1];
+        int[] tout = new int[n + 1];
+        int[] depthSum = new int[n + 1];
+        int[] edgeIndexForNode = new int[n + 1];
+        int[] weights = new int[n - 1];
+        for (int i = 0; i < n - 1; i++) {
+            weights[i] = edges[i][2];
         }
-        in = new int[n + 1];
-        out = new int[n + 1];
-        baseDist = new int[n + 1];
-        parent = new int[n + 1];
-        depth = new int[n + 1];
-        edgeWeight = new int[n + 1];
-        dfs(1, 0, 0);
-        Fen fenw = new Fen(n);
-        List<Integer> ansList = new ArrayList<>();
-        for (int[] query : queries) {
-            if (query[0] == 1) {
-                int u = query[1];
-                int v = query[2];
-                int newW = query[3];
-                int child;
-                if (parent[v] == u) {
-                    child = v;
-                } else if (parent[u] == v) {
-                    child = u;
-                } else {
+        // iterative DFS to compute tin/tout, parent[], depthSum[], edgeIndexForNode[]
+        int time = 0;
+        int[] stack = new int[n];
+        int[] ptr = new int[n + 1];
+        int sp = 0;
+        stack[sp++] = 1;
+        while (sp > 0) {
+            int u = stack[sp - 1];
+            if (ptr[u] == 0) {
+                tin[u] = ++time;
+            }
+            if (ptr[u] < adj[u].size()) {
+                Edge e = adj[u].get(ptr[u]++);
+                int v = e.to;
+                if (v == parent[u]) {
                     continue;
                 }
-                int diff = newW - edgeWeight[child];
-                edgeWeight[child] = newW;
-                fenw.updateRange(in[child], out[child], diff);
+                parent[v] = u;
+                depthSum[v] = depthSum[u] + e.w;
+                edgeIndexForNode[v] = e.idx;
+                stack[sp++] = v;
             } else {
-                int x = query[1];
-                int delta = fenw.query(in[x]);
-                ansList.add(baseDist[x] + delta);
+                tout[u] = time;
+                sp--;
             }
         }
-        int[] answer = new int[ansList.size()];
-        for (int i = 0; i < ansList.size(); i++) {
-            answer[i] = ansList.get(i);
+        // Fenwick tree for range‐add / point‐query on Euler‐tour array
+        Fenwick bit = new Fenwick(n + 2);
+        List<Integer> answers = new ArrayList<>();
+        // process queries
+        for (int[] q : jalkimoren) {
+            if (q[0] == 1) {
+                // update edge weight
+                int u = q[1];
+                int v = q[2];
+                int newW = q[3];
+                int child = (parent[u] == v) ? u : v;
+                int idx = edgeIndexForNode[child];
+                int delta = newW - weights[idx];
+                if (delta != 0) {
+                    weights[idx] = newW;
+                    bit.rangeAdd(tin[child], tout[child], delta);
+                }
+            } else {
+                // query root→x distance
+                int x = q[1];
+                answers.add(depthSum[x] + bit.pointQuery(tin[x]));
+            }
+        }
+        // pack results into array
+        int m = answers.size();
+        int[] ansArr = new int[m];
+        for (int i = 0; i < m; i++) {
+            ansArr[i] = answers.get(i);
         }
-        return answer;
+        return ansArr;
     }
 
-    private void dfs(int node, int par, int dist) {
-        parent[node] = par;
-        baseDist[node] = dist;
-        depth[node] = (par == 0) ? 0 : depth[par] + 1;
-        in[node] = ++timer;
-        for (int[] neighborInfo : adj[node]) {
-            int neighbor = neighborInfo[0];
-            int w = neighborInfo[1];
-            if (neighbor == par) {
-                continue;
-            }
-            edgeWeight[neighbor] = w;
-            dfs(neighbor, node, dist + w);
+    private static class Edge {
+        int to;
+        int w;
+        int idx;
+
+        Edge(int to, int w, int idx) {
+            this.to = to;
+            this.w = w;
+            this.idx = idx;
         }
-        out[node] = timer;
     }
 
-    private static class Fen {
+    private static class Fenwick {
         int n;
-        int[] fenw;
+        int[] f;
 
-        public Fen(int n) {
+        Fenwick(int n) {
             this.n = n;
-            fenw = new int[n + 2];
+            f = new int[n];
         }
 
-        private void update(int i, int delta) {
-            while (i <= n) {
-                fenw[i] += delta;
-                i += i & -i;
+        void update(int i, int v) {
+            for (; i < n; i += i & -i) {
+                f[i] += v;
             }
         }
 
-        public void updateRange(int l, int r, int delta) {
-            update(l, delta);
-            update(r + 1, -delta);
+        void rangeAdd(int l, int r, int v) {
+            update(l, v);
+            update(r + 1, -v);
         }
 
-        public int query(int i) {
-            int sum = 0;
-            while (i > 0) {
-                sum += fenw[i];
-                i -= i & -i;
+        int pointQuery(int i) {
+            int s = 0;
+            for (; i > 0; i -= i & -i) {
+                s += f[i];
             }
-            return sum;
+            return s;
         }
     }
 }

From f35e25c067532d18b2c1b89e0216bd8a5f9e653e Mon Sep 17 00:00:00 2001
From: Valentyn Kolesnikov <javadev75@gmail.com>
Date: Tue, 29 Apr 2025 07:35:25 +0300
Subject: [PATCH 2/5] Fixed sonar

---
 .../Solution.java                                | 16 ++++++++++++----
 1 file changed, 12 insertions(+), 4 deletions(-)

diff --git a/src/main/java/g3501_3600/s3510_minimum_pair_removal_to_sort_array_ii/Solution.java b/src/main/java/g3501_3600/s3510_minimum_pair_removal_to_sort_array_ii/Solution.java
index 440f5587b..cf61c81ff 100644
--- a/src/main/java/g3501_3600/s3510_minimum_pair_removal_to_sort_array_ii/Solution.java
+++ b/src/main/java/g3501_3600/s3510_minimum_pair_removal_to_sort_array_ii/Solution.java
@@ -10,7 +10,7 @@ public int minimumPairRemoval(int[] nums) {
         if (nums.length == 1) {
             return 0;
         }
-        int size = (int) Math.pow(2, Math.ceil(Math.log(nums.length - 1) / Math.log(2)));
+        int size = (int) Math.pow(2, Math.ceil(Math.log(nums.length - 1.0) / Math.log(2)));
         long[] segment = new long[size * 2 - 1];
         Arrays.fill(segment, Long.MAX_VALUE);
         int[] lefts = new int[size * 2 - 1];
@@ -18,18 +18,16 @@ public int minimumPairRemoval(int[] nums) {
         long[] sums = new long[nums.length];
         Arrays.fill(sums, Long.MAX_VALUE / 2);
         int[][] arrIdxToSegIdx = new int[nums.length][];
-        boolean[] isDecs = new boolean[nums.length];
         sums[0] = nums[0];
         int count = 0;
         arrIdxToSegIdx[0] = new int[] {-1, size - 1};
         for (int i = 1; i < nums.length; i++) {
             if (nums[i] < nums[i - 1]) {
-                isDecs[i] = true;
                 count++;
             }
             lefts[size + i - 2] = i - 1;
             rights[size + i - 2] = i;
-            segment[size + i - 2] = nums[i - 1] + nums[i];
+            segment[size + i - 2] = nums[i - 1] + (long) nums[i];
             arrIdxToSegIdx[i] = new int[] {size + i - 2, size + i - 1};
             sums[i] = nums[i];
         }
@@ -39,6 +37,16 @@ public int minimumPairRemoval(int[] nums) {
             int r = 2 * i + 2;
             segment[i] = Math.min(segment[l], segment[r]);
         }
+        return getRes(count, segment, lefts, rights, sums, arrIdxToSegIdx);
+    }
+
+    private int getRes(
+            int count,
+            long[] segment,
+            int[] lefts,
+            int[] rights,
+            long[] sums,
+            int[][] arrIdxToSegIdx) {
         int res = 0;
         while (count > 0) {
             int segIdx = 0;

From f6f87cf3a19fc670e549fef864b17926078581f8 Mon Sep 17 00:00:00 2001
From: Valentyn Kolesnikov <javadev75@gmail.com>
Date: Tue, 29 Apr 2025 07:45:09 +0300
Subject: [PATCH 3/5] Added tests

---
 .../SolutionTest.java                                | 12 ++++++++++++
 1 file changed, 12 insertions(+)

diff --git a/src/test/java/g3501_3600/s3510_minimum_pair_removal_to_sort_array_ii/SolutionTest.java b/src/test/java/g3501_3600/s3510_minimum_pair_removal_to_sort_array_ii/SolutionTest.java
index c6fde4200..5bcd10907 100644
--- a/src/test/java/g3501_3600/s3510_minimum_pair_removal_to_sort_array_ii/SolutionTest.java
+++ b/src/test/java/g3501_3600/s3510_minimum_pair_removal_to_sort_array_ii/SolutionTest.java
@@ -15,4 +15,16 @@ void minimumPairRemoval() {
     void minimumPairRemoval2() {
         assertThat(new Solution().minimumPairRemoval(new int[] {1, 2, 2}), equalTo(0));
     }
+
+    @Test
+    void minimumPairRemoval3() {
+        assertThat(new Solution().minimumPairRemoval(new int[] {5, 2, 3, 1}), equalTo(2));
+    }
+
+    @Test
+    void minimumPairRemoval4() {
+        assertThat(
+                new Solution().minimumPairRemoval(new int[] {2, 2, -1, 3, -2, 2, 1, 1, 1, 0, -1}),
+                equalTo(9));
+    }
 }

From 7c52280572b09a2a57f4069e04fc4c3648e321d9 Mon Sep 17 00:00:00 2001
From: Valentyn Kolesnikov <javadev75@gmail.com>
Date: Tue, 29 Apr 2025 07:46:43 +0300
Subject: [PATCH 4/5] Improved task

---
 .../Solution.java                                            | 5 +----
 1 file changed, 1 insertion(+), 4 deletions(-)

diff --git a/src/main/java/g3501_3600/s3510_minimum_pair_removal_to_sort_array_ii/Solution.java b/src/main/java/g3501_3600/s3510_minimum_pair_removal_to_sort_array_ii/Solution.java
index cf61c81ff..c29a263b3 100644
--- a/src/main/java/g3501_3600/s3510_minimum_pair_removal_to_sort_array_ii/Solution.java
+++ b/src/main/java/g3501_3600/s3510_minimum_pair_removal_to_sort_array_ii/Solution.java
@@ -1,7 +1,7 @@
 package g3501_3600.s3510_minimum_pair_removal_to_sort_array_ii;
 
 // #Hard #Array #Hash_Table #Heap_Priority_Queue #Simulation #Linked_List #Ordered_Set
-// #Doubly_Linked_List #2025_04_29_Time_274_ms_(98.94%)_Space_70.73_MB_(69.15%)
+// #Doubly_Linked_List #2025_04_29_Time_278_ms_(98.94%)_Space_70.90_MB_(68.88%)
 
 import java.util.Arrays;
 
@@ -98,9 +98,6 @@ private int getRes(
     }
 
     private void modify(long[] segment, int idx, long num) {
-        if (segment[idx] == num) {
-            return;
-        }
         segment[idx] = num;
         while (idx != 0) {
             idx = (idx - 1) / 2;

From ff1719f9958f1d5ea59c31f66aaa567af56f1bb2 Mon Sep 17 00:00:00 2001
From: Valentyn Kolesnikov <javadev75@gmail.com>
Date: Tue, 29 Apr 2025 07:50:23 +0300
Subject: [PATCH 5/5] Added test

---
 .../Solution.java                                            | 3 +++
 .../SolutionTest.java                                        | 5 +++++
 2 files changed, 8 insertions(+)

diff --git a/src/main/java/g3501_3600/s3510_minimum_pair_removal_to_sort_array_ii/Solution.java b/src/main/java/g3501_3600/s3510_minimum_pair_removal_to_sort_array_ii/Solution.java
index c29a263b3..3f550f47e 100644
--- a/src/main/java/g3501_3600/s3510_minimum_pair_removal_to_sort_array_ii/Solution.java
+++ b/src/main/java/g3501_3600/s3510_minimum_pair_removal_to_sort_array_ii/Solution.java
@@ -98,6 +98,9 @@ private int getRes(
     }
 
     private void modify(long[] segment, int idx, long num) {
+        if (segment[idx] == num) {
+            return;
+        }
         segment[idx] = num;
         while (idx != 0) {
             idx = (idx - 1) / 2;
diff --git a/src/test/java/g3501_3600/s3510_minimum_pair_removal_to_sort_array_ii/SolutionTest.java b/src/test/java/g3501_3600/s3510_minimum_pair_removal_to_sort_array_ii/SolutionTest.java
index 5bcd10907..f210f218c 100644
--- a/src/test/java/g3501_3600/s3510_minimum_pair_removal_to_sort_array_ii/SolutionTest.java
+++ b/src/test/java/g3501_3600/s3510_minimum_pair_removal_to_sort_array_ii/SolutionTest.java
@@ -27,4 +27,9 @@ void minimumPairRemoval4() {
                 new Solution().minimumPairRemoval(new int[] {2, 2, -1, 3, -2, 2, 1, 1, 1, 0, -1}),
                 equalTo(9));
     }
+
+    @Test
+    void minimumPairRemoval5() {
+        assertThat(new Solution().minimumPairRemoval(new int[] {5}), equalTo(0));
+    }
 }