diff --git a/src/main/java/g3101_3200/s3161_block_placement_queries/Solution.java b/src/main/java/g3101_3200/s3161_block_placement_queries/Solution.java index 3bd92d82e..0986757cd 100644 --- a/src/main/java/g3101_3200/s3161_block_placement_queries/Solution.java +++ b/src/main/java/g3101_3200/s3161_block_placement_queries/Solution.java @@ -1,107 +1,112 @@ package g3101_3200.s3161_block_placement_queries; // #Hard #Array #Binary_Search #Segment_Tree #Binary_Indexed_Tree -// #2024_05_30_Time_137_ms_(99.38%)_Space_143.7_MB_(54.52%) +// #2025_03_16_Time_47_ms_(100.00%)_Space_144.38_MB_(56.41%) -import java.util.ArrayList; +import java.util.Arrays; import java.util.List; public class Solution { - private static class Seg { - private final int start; - private final int end; - private int min; - private int max; - private int len; - private boolean obstacle; - private Seg left; - private Seg right; - - public static Seg init(int n) { - return new Seg(0, n); - } - - private Seg(int start, int end) { - this.start = start; - this.end = end; - if (start >= end) { - return; + public List getResults(int[][] queries) { + int m = queries.length; + int[] pos = new int[m + 1]; + int size = 0; + pos[size++] = 0; + int max = 0; + for (int[] q : queries) { + max = Math.max(max, q[1]); + if (q[0] == 1) { + pos[size++] = q[1]; } - int mid = start + ((end - start) >> 1); - left = new Seg(start, mid); - right = new Seg(mid + 1, end); - refresh(); } + Arrays.sort(pos, 0, size); + max++; + UnionFind left = new UnionFind(max + 1); + UnionFind right = new UnionFind(max + 1); + BIT bit = new BIT(max); + initializePositions(size, pos, bit, left, right, max); + return List.of(getBooleans(queries, m, size, left, right, bit)); + } - public void set(int i) { - if (i < start || i > end) { - return; - } else if (i == start && i == end) { - obstacle = true; - min = max = start; - return; + private void initializePositions( + int size, int[] pos, BIT bit, UnionFind left, UnionFind right, int max) { + for (int i = 1; i < size; i++) { + int pre = pos[i - 1]; + int cur = pos[i]; + bit.update(cur, cur - pre); + for (int j = pre + 1; j < cur; j++) { + left.parent[j] = pre; + right.parent[j] = cur; } - left.set(i); - right.set(i); - refresh(); } + for (int j = pos[size - 1] + 1; j < max; j++) { + left.parent[j] = pos[size - 1]; + right.parent[j] = max; + } + } - private void refresh() { - if (left.obstacle) { - min = left.min; - if (right.obstacle) { - max = right.max; - len = Math.max(right.min - left.max, Math.max(left.len, right.len)); - } else { - max = left.max; - len = Math.max(left.len, right.end - left.max); - } - obstacle = true; - } else if (right.obstacle) { - min = right.min; - max = right.max; - len = Math.max(right.len, right.min - left.start); - obstacle = true; + private Boolean[] getBooleans( + int[][] queries, int m, int size, UnionFind left, UnionFind right, BIT bit) { + Boolean[] ans = new Boolean[m - size + 1]; + int index = ans.length - 1; + for (int i = m - 1; i >= 0; i--) { + int[] q = queries[i]; + int x = q[1]; + int pre = left.find(x - 1); + if (q[0] == 1) { + int next = right.find(x + 1); + left.parent[x] = pre; + right.parent[x] = next; + bit.update(next, next - pre); } else { - len = end - start; + int maxGap = Math.max(bit.query(pre), x - pre); + ans[index--] = maxGap >= q[2]; } } + return ans; + } + + private static final class BIT { + int n; + int[] tree; - public void max(int n, int[] t) { - if (end <= n) { - t[0] = Math.max(t[0], len); - if (obstacle) { - t[1] = max; - } - return; + public BIT(int n) { + this.n = n; + tree = new int[n]; + } + + public void update(int i, int v) { + while (i < n) { + tree[i] = Math.max(tree[i], v); + i += i & -i; } - left.max(n, t); - if (!right.obstacle || right.min >= n) { - return; + } + + public int query(int i) { + int result = 0; + while (i > 0) { + result = Math.max(result, tree[i]); + i &= i - 1; } - t[0] = Math.max(t[0], right.min - t[1]); - right.max(n, t); + return result; } } - public List getResults(int[][] queries) { - int max = 0; - for (int[] i : queries) { - max = Math.max(max, i[1]); + private static final class UnionFind { + private final int[] parent; + + public UnionFind(int n) { + parent = new int[n]; + for (int i = 1; i < n; i++) { + parent[i] = i; + } } - Seg root = Seg.init(max); - root.set(0); - List res = new ArrayList<>(queries.length); - for (int[] i : queries) { - if (i[0] == 1) { - root.set(i[1]); - } else { - int[] t = new int[2]; - root.max(i[1], t); - res.add(Math.max(t[0], i[1] - t[1]) >= i[2]); + public int find(int x) { + if (parent[x] != x) { + parent[x] = find(parent[x]); } + return parent[x]; } - return res; } } diff --git a/src/main/java/g3301_3400/s3327_check_if_dfs_strings_are_palindromes/Solution.java b/src/main/java/g3301_3400/s3327_check_if_dfs_strings_are_palindromes/Solution.java index 8a858a2cb..e7617d788 100644 --- a/src/main/java/g3301_3400/s3327_check_if_dfs_strings_are_palindromes/Solution.java +++ b/src/main/java/g3301_3400/s3327_check_if_dfs_strings_are_palindromes/Solution.java @@ -1,76 +1,80 @@ package g3301_3400.s3327_check_if_dfs_strings_are_palindromes; // #Hard #Array #String #Hash_Table #Depth_First_Search #Tree #Hash_Function -// #2024_10_22_Time_159_ms_(90.40%)_Space_93.9_MB_(80.80%) - -import java.util.ArrayList; -import java.util.List; +// #2025_03_16_Time_70_ms_(100.00%)_Space_75.50_MB_(96.67%) public class Solution { - private final List> e = new ArrayList<>(); - private final StringBuilder stringBuilder = new StringBuilder(); - private String s; - private int now; - private int n; - private int[] l; - private int[] r; - private int[] p; - private char[] c; + private int time = 0; + private byte[] cs; + private int[][] graph; - private void dfs(int x) { - l[x] = now + 1; - for (int v : e.get(x)) { - dfs(v); + public boolean[] findAnswer(int[] parent, String s) { + int n = s.length(); + cs = s.getBytes(); + graph = new int[n][]; + final int[] childCount = new int[n]; + for (int i = 1; i < n; i++) { + childCount[parent[i]]++; } - stringBuilder.append(s.charAt(x)); - r[x] = ++now; - } - - private void matcher() { - c[0] = '~'; - c[1] = '#'; - for (int i = 1; i <= n; ++i) { - c[2 * i + 1] = '#'; - c[2 * i] = stringBuilder.charAt(i - 1); + for (int i = 0; i < n; i++) { + graph[i] = new int[childCount[i]]; + childCount[i] = 0; } - int j = 1; - int mid = 0; - int localR = 0; - while (j <= 2 * n + 1) { - if (j <= localR) { - p[j] = Math.min(p[(mid << 1) - j], localR - j + 1); - } - while (c[j - p[j]] == c[j + p[j]]) { - ++p[j]; - } - if (p[j] + j > localR) { - localR = p[j] + j - 1; - mid = j; - } - ++j; + for (int i = 1; i < n; i++) { + graph[parent[i]][childCount[parent[i]]++] = i; + } + byte[] dfsStr = new byte[n]; + int[] start = new int[n]; + int[] end = new int[n]; + dfs(0, dfsStr, start, end); + int[] lens = getRadius(dfsStr); + boolean[] ans = new boolean[n]; + for (int i = 0; i < n; i++) { + int l = start[i]; + int r = end[i]; + int center = l + r + 2; + ans[i] = lens[center] >= r - l + 1; } + return ans; } - public boolean[] findAnswer(int[] parent, String s) { - n = parent.length; - this.s = s; - for (int i = 0; i < n; ++i) { - e.add(new ArrayList<>()); + private void dfs(int u, byte[] dfsStr, int[] start, int[] end) { + start[u] = time; + for (int v : graph[u]) { + dfs(v, dfsStr, start, end); } - for (int i = 1; i < n; ++i) { - e.get(parent[i]).add(i); + dfsStr[time] = cs[u]; + end[u] = time++; + } + + private int[] getRadius(byte[] cs) { + int n = cs.length; + byte[] t = new byte[2 * n + 3]; + int m = 0; + t[m++] = '@'; + t[m++] = '#'; + for (byte c : cs) { + t[m++] = c; + t[m++] = '#'; } - l = new int[n]; - r = new int[n]; - dfs(0); - c = new char[2 * n + 10]; - p = new int[2 * n + 10]; - matcher(); - boolean[] ans = new boolean[n]; - for (int i = 0; i < n; ++i) { - int mid = (2 * r[i] - 2 * l[i] + 1) / 2 + 2 * l[i]; - ans[i] = p[mid] - 1 >= r[i] - l[i] + 1; + t[m++] = '$'; + int[] lens = new int[m]; + int center = 0; + int right = 0; + for (int i = 2; i < m - 2; i++) { + int len = 0; + if (i < right) { + len = Math.min(lens[2 * center - i], right - i); + } + while (t[i + len + 1] == t[i - len - 1]) { + len++; + } + if (right < i + len) { + right = i + len; + center = i; + } + lens[i] = len; } - return ans; + return lens; } }