Skip to content

Improved tasks 3161, 3327 #779

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 1 commit 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
162 changes: 88 additions & 74 deletions src/main/kotlin/g3101_3200/s3161_block_placement_queries/Solution.kt
Original file line number Diff line number Diff line change
@@ -1,104 +1,118 @@
package g3101_3200.s3161_block_placement_queries

// #Hard #Array #Binary_Search #Segment_Tree #Binary_Indexed_Tree
// #2024_05_30_Time_1701_ms_(100.00%)_Space_174.7_MB_(33.33%)
// #2025_03_16_Time_100_ms_(100.00%)_Space_144.97_MB_(43.75%)

import kotlin.math.max

class Solution {
private class Seg private constructor(private val start: Int, private val end: Int) {
private var min = 0
private var max = 0
private var len = 0
private var obstacle = false
private lateinit var left: Seg
private lateinit var right: Seg

init {
if (start < end) {
val mid = start + ((end - start) shr 1)
left = Seg(start, mid)
right = Seg(mid + 1, end)
refresh()
fun getResults(queries: Array<IntArray>): List<Boolean> {
val m = queries.size
val pos = IntArray(m + 1)
var size = 0
pos[size++] = 0
var max = 0
for (q in queries) {
max = max(max.toDouble(), q[1].toDouble()).toInt()
if (q[0] == 1) {
pos[size++] = q[1]
}
}
pos.sort(0, size)
max++
val left = UnionFind(max + 1)
val right = UnionFind(max + 1)
val bit = BIT(max)
initializePositions(size, pos, bit, left, right, max)
return listOf<Boolean>(*getBooleans(queries, m, size, left, right, bit))
}

fun set(i: Int) {
if (i < start || i > end) {
return
} else if (i == start && i == end) {
obstacle = true
max = start
min = max
return
private fun initializePositions(
size: Int,
pos: IntArray,
bit: BIT,
left: UnionFind,
right: UnionFind,
max: Int,
) {
for (i in 1..<size) {
val pre = pos[i - 1]
val cur = pos[i]
bit.update(cur, cur - pre)
for (j in pre + 1..<cur) {
left.parent[j] = pre
right.parent[j] = cur
}
left.set(i)
right.set(i)
refresh()
}
for (j in pos[size - 1] + 1..<max) {
left.parent[j] = pos[size - 1]
right.parent[j] = max
}
}

private fun refresh() {
if (left.obstacle) {
min = left.min
if (right.obstacle) {
max = right.max
len = max((right.min - left.max), max(left.len, right.len))
} else {
max = left.max
len = max(left.len, (right.end - left.max))
}
obstacle = true
} else if (right.obstacle) {
min = right.min
max = right.max
len = max(right.len, (right.min - left.start))
obstacle = true
private fun getBooleans(
queries: Array<IntArray>,
m: Int,
size: Int,
left: UnionFind,
right: UnionFind,
bit: BIT,
): Array<Boolean> {
val ans = Array<Boolean>(m - size + 1) { false }
var index = ans.size - 1
for (i in m - 1 downTo 0) {
val q = queries[i]
val x = q[1]
val pre = left.find(x - 1)
if (q[0] == 1) {
val next = right.find(x + 1)
left.parent[x] = pre
right.parent[x] = next
bit.update(next, next - pre)
} else {
len = end - start
val maxGap = max(bit.query(pre).toDouble(), (x - pre).toDouble()).toInt()
ans[index--] = maxGap >= q[2]
}
}
return ans
}

fun max(n: Int, t: IntArray) {
if (end <= n) {
t[0] = max(t[0], len)
if (obstacle) {
t[1] = max
}
return
}
left.max(n, t)
if (!right.obstacle || right.min >= n) {
return
private class BIT(var n: Int) {
var tree: IntArray = IntArray(n)

fun update(i: Int, v: Int) {
var i = i
while (i < n) {
tree[i] = max(tree[i].toDouble(), v.toDouble()).toInt()
i += i and -i
}
t[0] = max(t[0], (right.min - t[1]))
right.max(n, t)
}

companion object {
fun init(n: Int): Seg {
return Seg(0, n)
fun query(i: Int): Int {
var i = i
var result = 0
while (i > 0) {
result = max(result.toDouble(), tree[i].toDouble()).toInt()
i = i and i - 1
}
return result
}
}

fun getResults(queries: Array<IntArray>): List<Boolean> {
var max = 0
for (i in queries) {
max = max(max, i[1])
private class UnionFind(n: Int) {
val parent: IntArray = IntArray(n)

init {
for (i in 1..<n) {
parent[i] = i
}
}
val root = Seg.init(max)
root.set(0)

val res: MutableList<Boolean> = ArrayList(queries.size)
for (i in queries) {
if (i[0] == 1) {
root.set(i[1])
} else {
val t = IntArray(2)
root.max(i[1], t)
res.add(max(t[0], (i[1] - t[1])) >= i[2])
fun find(x: Int): Int {
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,75 +1,82 @@
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_165_ms_(100.00%)_Space_88.9_MB_(66.67%)
// #2025_03_16_Time_86_ms_(100.00%)_Space_93.26_MB_(80.00%)

import kotlin.math.min

class Solution {
private val e: MutableList<MutableList<Int>> = ArrayList<MutableList<Int>>()
private val stringBuilder = StringBuilder()
private var s: String? = null
private var now = 0
private var n = 0
private lateinit var l: IntArray
private lateinit var r: IntArray
private lateinit var p: IntArray
private lateinit var c: CharArray
private var time = 0
private lateinit var cs: ByteArray
private lateinit var graph: Array<IntArray?>

private fun dfs(x: Int) {
l[x] = now + 1
for (v in e[x]) {
dfs(v)
fun findAnswer(parent: IntArray, s: String): BooleanArray {
val n = s.length
cs = s.toByteArray()
graph = arrayOfNulls<IntArray>(n)
val childCount = IntArray(n)
for (i in 1..<n) {
childCount[parent[i]]++
}
stringBuilder.append(s!![x])
r[x] = ++now
}

private fun matcher() {
c[0] = '~'
c[1] = '#'
for (i in 1..n) {
c[2 * i + 1] = '#'
c[2 * i] = stringBuilder[i - 1]
for (i in 0..<n) {
graph[i] = IntArray(childCount[i])
childCount[i] = 0
}
var j = 1
var mid = 0
var localR = 0
while (j <= 2 * n + 1) {
if (j <= localR) {
p[j] = min(p[(mid shl 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 (i in 1..<n) {
graph[parent[i]]!![childCount[parent[i]]++] = i
}
val dfsStr = ByteArray(n)
val start = IntArray(n)
val end = IntArray(n)
dfs(0, dfsStr, start, end)
val lens = getRadius(dfsStr)
val ans = BooleanArray(n)
for (i in 0..<n) {
val l = start[i]
val r = end[i]
val center = l + r + 2
ans[i] = lens[center] >= r - l + 1
}
return ans
}

fun findAnswer(parent: IntArray, s: String): BooleanArray {
n = parent.size
this.s = s
for (i in 0 until n) {
e.add(ArrayList<Int>())
private fun dfs(u: Int, dfsStr: ByteArray, start: IntArray, end: IntArray) {
start[u] = time
for (v in graph[u]!!) {
dfs(v, dfsStr, start, end)
}
for (i in 1 until n) {
e[parent[i]].add(i)
dfsStr[time] = cs[u]
end[u] = time++
}

private fun getRadius(cs: ByteArray): IntArray {
val n = cs.size
val t = ByteArray(2 * n + 3)
var m = 0
t[m++] = '@'.code.toByte()
t[m++] = '#'.code.toByte()
for (c in cs) {
t[m++] = c
t[m++] = '#'.code.toByte()
}
l = IntArray(n)
r = IntArray(n)
dfs(0)
c = CharArray(2 * n + 10)
p = IntArray(2 * n + 10)
matcher()
val ans = BooleanArray(n)
for (i in 0 until n) {
val mid = (2 * r[i] - 2 * l[i] + 1) / 2 + 2 * l[i]
ans[i] = p[mid] - 1 >= r[i] - l[i] + 1
t[m++] = '$'.code.toByte()
val lens = IntArray(m)
var center = 0
var right = 0
for (i in 2..<m - 2) {
var len = 0
if (i < right) {
len = min(lens[2 * center - i].toDouble(), (right - i).toDouble()).toInt()
}
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
}
}