Skip to content

Commit 203a5bb

Browse files
committed
Improved tasks 3161, 3327
1 parent 29b648f commit 203a5bb

File tree

2 files changed

+152
-131
lines changed
  • src/main/kotlin
    • g3101_3200/s3161_block_placement_queries
    • g3301_3400/s3327_check_if_dfs_strings_are_palindromes

2 files changed

+152
-131
lines changed
Original file line numberDiff line numberDiff line change
@@ -1,104 +1,118 @@
11
package g3101_3200.s3161_block_placement_queries
22

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

66
import kotlin.math.max
77

88
class Solution {
9-
private class Seg private constructor(private val start: Int, private val end: Int) {
10-
private var min = 0
11-
private var max = 0
12-
private var len = 0
13-
private var obstacle = false
14-
private lateinit var left: Seg
15-
private lateinit var right: Seg
16-
17-
init {
18-
if (start < end) {
19-
val mid = start + ((end - start) shr 1)
20-
left = Seg(start, mid)
21-
right = Seg(mid + 1, end)
22-
refresh()
9+
fun getResults(queries: Array<IntArray>): List<Boolean> {
10+
val m = queries.size
11+
val pos = IntArray(m + 1)
12+
var size = 0
13+
pos[size++] = 0
14+
var max = 0
15+
for (q in queries) {
16+
max = max(max.toDouble(), q[1].toDouble()).toInt()
17+
if (q[0] == 1) {
18+
pos[size++] = q[1]
2319
}
2420
}
21+
pos.sort(0, size)
22+
max++
23+
val left = UnionFind(max + 1)
24+
val right = UnionFind(max + 1)
25+
val bit = BIT(max)
26+
initializePositions(size, pos, bit, left, right, max)
27+
return listOf<Boolean>(*getBooleans(queries, m, size, left, right, bit))
28+
}
2529

26-
fun set(i: Int) {
27-
if (i < start || i > end) {
28-
return
29-
} else if (i == start && i == end) {
30-
obstacle = true
31-
max = start
32-
min = max
33-
return
30+
private fun initializePositions(
31+
size: Int,
32+
pos: IntArray,
33+
bit: BIT,
34+
left: UnionFind,
35+
right: UnionFind,
36+
max: Int,
37+
) {
38+
for (i in 1..<size) {
39+
val pre = pos[i - 1]
40+
val cur = pos[i]
41+
bit.update(cur, cur - pre)
42+
for (j in pre + 1..<cur) {
43+
left.parent[j] = pre
44+
right.parent[j] = cur
3445
}
35-
left.set(i)
36-
right.set(i)
37-
refresh()
3846
}
47+
for (j in pos[size - 1] + 1..<max) {
48+
left.parent[j] = pos[size - 1]
49+
right.parent[j] = max
50+
}
51+
}
3952

40-
private fun refresh() {
41-
if (left.obstacle) {
42-
min = left.min
43-
if (right.obstacle) {
44-
max = right.max
45-
len = max((right.min - left.max), max(left.len, right.len))
46-
} else {
47-
max = left.max
48-
len = max(left.len, (right.end - left.max))
49-
}
50-
obstacle = true
51-
} else if (right.obstacle) {
52-
min = right.min
53-
max = right.max
54-
len = max(right.len, (right.min - left.start))
55-
obstacle = true
53+
private fun getBooleans(
54+
queries: Array<IntArray>,
55+
m: Int,
56+
size: Int,
57+
left: UnionFind,
58+
right: UnionFind,
59+
bit: BIT,
60+
): Array<Boolean> {
61+
val ans = Array<Boolean>(m - size + 1) { false }
62+
var index = ans.size - 1
63+
for (i in m - 1 downTo 0) {
64+
val q = queries[i]
65+
val x = q[1]
66+
val pre = left.find(x - 1)
67+
if (q[0] == 1) {
68+
val next = right.find(x + 1)
69+
left.parent[x] = pre
70+
right.parent[x] = next
71+
bit.update(next, next - pre)
5672
} else {
57-
len = end - start
73+
val maxGap = max(bit.query(pre).toDouble(), (x - pre).toDouble()).toInt()
74+
ans[index--] = maxGap >= q[2]
5875
}
5976
}
77+
return ans
78+
}
6079

61-
fun max(n: Int, t: IntArray) {
62-
if (end <= n) {
63-
t[0] = max(t[0], len)
64-
if (obstacle) {
65-
t[1] = max
66-
}
67-
return
68-
}
69-
left.max(n, t)
70-
if (!right.obstacle || right.min >= n) {
71-
return
80+
private class BIT(var n: Int) {
81+
var tree: IntArray = IntArray(n)
82+
83+
fun update(i: Int, v: Int) {
84+
var i = i
85+
while (i < n) {
86+
tree[i] = max(tree[i].toDouble(), v.toDouble()).toInt()
87+
i += i and -i
7288
}
73-
t[0] = max(t[0], (right.min - t[1]))
74-
right.max(n, t)
7589
}
7690

77-
companion object {
78-
fun init(n: Int): Seg {
79-
return Seg(0, n)
91+
fun query(i: Int): Int {
92+
var i = i
93+
var result = 0
94+
while (i > 0) {
95+
result = max(result.toDouble(), tree[i].toDouble()).toInt()
96+
i = i and i - 1
8097
}
98+
return result
8199
}
82100
}
83101

84-
fun getResults(queries: Array<IntArray>): List<Boolean> {
85-
var max = 0
86-
for (i in queries) {
87-
max = max(max, i[1])
102+
private class UnionFind(n: Int) {
103+
val parent: IntArray = IntArray(n)
104+
105+
init {
106+
for (i in 1..<n) {
107+
parent[i] = i
108+
}
88109
}
89-
val root = Seg.init(max)
90-
root.set(0)
91110

92-
val res: MutableList<Boolean> = ArrayList(queries.size)
93-
for (i in queries) {
94-
if (i[0] == 1) {
95-
root.set(i[1])
96-
} else {
97-
val t = IntArray(2)
98-
root.max(i[1], t)
99-
res.add(max(t[0], (i[1] - t[1])) >= i[2])
111+
fun find(x: Int): Int {
112+
if (parent[x] != x) {
113+
parent[x] = find(parent[x])
100114
}
115+
return parent[x]
101116
}
102-
return res
103117
}
104118
}
Original file line numberDiff line numberDiff line change
@@ -1,75 +1,82 @@
11
package g3301_3400.s3327_check_if_dfs_strings_are_palindromes
22

33
// #Hard #Array #String #Hash_Table #Depth_First_Search #Tree #Hash_Function
4-
// #2024_10_22_Time_165_ms_(100.00%)_Space_88.9_MB_(66.67%)
4+
// #2025_03_16_Time_86_ms_(100.00%)_Space_93.26_MB_(80.00%)
55

66
import kotlin.math.min
77

88
class Solution {
9-
private val e: MutableList<MutableList<Int>> = ArrayList<MutableList<Int>>()
10-
private val stringBuilder = StringBuilder()
11-
private var s: String? = null
12-
private var now = 0
13-
private var n = 0
14-
private lateinit var l: IntArray
15-
private lateinit var r: IntArray
16-
private lateinit var p: IntArray
17-
private lateinit var c: CharArray
9+
private var time = 0
10+
private lateinit var cs: ByteArray
11+
private lateinit var graph: Array<IntArray?>
1812

19-
private fun dfs(x: Int) {
20-
l[x] = now + 1
21-
for (v in e[x]) {
22-
dfs(v)
13+
fun findAnswer(parent: IntArray, s: String): BooleanArray {
14+
val n = s.length
15+
cs = s.toByteArray()
16+
graph = arrayOfNulls<IntArray>(n)
17+
val childCount = IntArray(n)
18+
for (i in 1..<n) {
19+
childCount[parent[i]]++
2320
}
24-
stringBuilder.append(s!![x])
25-
r[x] = ++now
26-
}
27-
28-
private fun matcher() {
29-
c[0] = '~'
30-
c[1] = '#'
31-
for (i in 1..n) {
32-
c[2 * i + 1] = '#'
33-
c[2 * i] = stringBuilder[i - 1]
21+
for (i in 0..<n) {
22+
graph[i] = IntArray(childCount[i])
23+
childCount[i] = 0
3424
}
35-
var j = 1
36-
var mid = 0
37-
var localR = 0
38-
while (j <= 2 * n + 1) {
39-
if (j <= localR) {
40-
p[j] = min(p[(mid shl 1) - j], (localR - j + 1))
41-
}
42-
while (c[j - p[j]] == c[j + p[j]]) {
43-
++p[j]
44-
}
45-
if (p[j] + j > localR) {
46-
localR = p[j] + j - 1
47-
mid = j
48-
}
49-
++j
25+
for (i in 1..<n) {
26+
graph[parent[i]]!![childCount[parent[i]]++] = i
27+
}
28+
val dfsStr = ByteArray(n)
29+
val start = IntArray(n)
30+
val end = IntArray(n)
31+
dfs(0, dfsStr, start, end)
32+
val lens = getRadius(dfsStr)
33+
val ans = BooleanArray(n)
34+
for (i in 0..<n) {
35+
val l = start[i]
36+
val r = end[i]
37+
val center = l + r + 2
38+
ans[i] = lens[center] >= r - l + 1
5039
}
40+
return ans
5141
}
5242

53-
fun findAnswer(parent: IntArray, s: String): BooleanArray {
54-
n = parent.size
55-
this.s = s
56-
for (i in 0 until n) {
57-
e.add(ArrayList<Int>())
43+
private fun dfs(u: Int, dfsStr: ByteArray, start: IntArray, end: IntArray) {
44+
start[u] = time
45+
for (v in graph[u]!!) {
46+
dfs(v, dfsStr, start, end)
5847
}
59-
for (i in 1 until n) {
60-
e[parent[i]].add(i)
48+
dfsStr[time] = cs[u]
49+
end[u] = time++
50+
}
51+
52+
private fun getRadius(cs: ByteArray): IntArray {
53+
val n = cs.size
54+
val t = ByteArray(2 * n + 3)
55+
var m = 0
56+
t[m++] = '@'.code.toByte()
57+
t[m++] = '#'.code.toByte()
58+
for (c in cs) {
59+
t[m++] = c
60+
t[m++] = '#'.code.toByte()
6161
}
62-
l = IntArray(n)
63-
r = IntArray(n)
64-
dfs(0)
65-
c = CharArray(2 * n + 10)
66-
p = IntArray(2 * n + 10)
67-
matcher()
68-
val ans = BooleanArray(n)
69-
for (i in 0 until n) {
70-
val mid = (2 * r[i] - 2 * l[i] + 1) / 2 + 2 * l[i]
71-
ans[i] = p[mid] - 1 >= r[i] - l[i] + 1
62+
t[m++] = '$'.code.toByte()
63+
val lens = IntArray(m)
64+
var center = 0
65+
var right = 0
66+
for (i in 2..<m - 2) {
67+
var len = 0
68+
if (i < right) {
69+
len = min(lens[2 * center - i].toDouble(), (right - i).toDouble()).toInt()
70+
}
71+
while (t[i + len + 1] == t[i - len - 1]) {
72+
len++
73+
}
74+
if (right < i + len) {
75+
right = i + len
76+
center = i
77+
}
78+
lens[i] = len
7279
}
73-
return ans
80+
return lens
7481
}
7582
}

0 commit comments

Comments
 (0)