Skip to content

Improved tasks 3161, 3327 #1944

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
Mar 16, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
163 changes: 84 additions & 79 deletions src/main/java/g3101_3200/s3161_block_placement_queries/Solution.java
Original file line number Diff line number Diff line change
@@ -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<Boolean> 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<Boolean> 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<Boolean> 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;
}
}
Original file line number Diff line number Diff line change
@@ -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<List<Integer>> 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;
}
}