You can use a deque that you keep sorted.
At each step, if the first element in the deque (d.front.index) is older than k steps relative to the current step, pop it (d.popFront()).
Then, while the element at the current position in the array is smaller than the last element in the deque (d.back.value), pop elements from the deque (d.popBack()).
Finally, add the current value to the end of the deque (d.pushBack()).
At each step, d.front.value will be the smallest value of [step - k + 1, step].
You can store the deque as a linked list of size k. Then you will have access to the second element in it at all times, which will be the second smallest in [step - k + 1, step]. You have to be careful if you end up with only a single element due to popping every element. In that case, the ones popped might be the second smallest for future queries. You can keep these in another list that you handle similarly to the deque, see below for an example.
This is O(n) amortized, because each element in your array will enter and leave the deque at most once. It might seem like O(nk) because you will have some nested loops, but if you think about the total number of operations, you'll see that it is actually O(n).
Pseudocode
for i = 0, i < n:
if not d.empty and i - d.front.index >= k:
d.popFront()
while not d.empty and d.back.value > a[i]:
d.popBack()
d.pushBack({index = i, value = a[i]})
output d.front.value as the minimum value in [i - k + 1, i]
Code for tracking the second minimum is left as an exercise.
For your example:
a = {12, 1, 78, 90, 57, 89, 56}, k = 3
d = {12}
d = {1} (12 popped, track this)
d = {1, 78} => we have to output smallest and second smallest in [0, 2].
=> smallest is always the first in the deque, so 1
=> second = min(12 [this was popped], 78) = 12
d = {1, 78, 90)
=> smallest 1, second is 78 (12 is too old now)
d = {57}
=> 1 popped for being too old, the others for being too large
=> smallest = 57, second = 78 (last popped)
d = {57, 89}
=> smallest = 57, second = 89
d = {56}
=> smallest = 56, second = 57
Basically, you keep an array for the second smallest. This will contain the popped values that aren't yet too old. These will also be sorted, but descendingly.
Example run for this approach, where d2 is the second array:
a = {12, 1, 78, 90, 57, 89, 56}
d = {12}, d2 = {}
d = {1}, d2 = {12}
d = {1, 78}, d2 = {12}
=> output 1, 12
d = {1, 78, 90}, d2 = {} - 12 was too old
=> output 1, 78
d = {57} d2 = {90, 78}
=> output 57, 78
d = {57, 89} d2 = {90} - 78 too old
=> output 57, 89 (if we had 91 instead of 89, we'd have output the 90 in d2)
d = {56} d2 = {89, 57}
=> output 56, 57