package main
import (
"bufio"
"fmt"
"os"
"strconv"
"strings"
)
type Node struct {
sum, max_pref, min_pref, max_suff, min_suff int
}
var tree []Node
func max(a, b int) int {
if a > b {
return a
}
return b
}
func min(a, b int) int {
if a < b {
return a
}
return b
}
func merge(l, r Node) Node {
return Node{
sum: l.sum + r.sum,
max_pref: max(l.max_pref, l.sum+r.max_pref),
min_pref: min(l.min_pref, l.sum+r.min_pref),
max_suff: max(r.max_suff, r.sum+l.max_suff),
min_suff: min(r.min_suff, r.sum+l.min_suff),
}
}
func build(node, l, r int) {
if l == r {
tree[node] = Node{
sum: -1,
max_pref: -1,
min_pref: -1,
max_suff: -1,
min_suff: -1,
}
return
}
mid := l + (r-l)/2
build(node*2, l, mid)
build(node*2+1, mid+1, r)
tree[node] = merge(tree[node*2], tree[node*2+1])
}
func update(node, l, r, idx, val int) {
if l == r {
tree[node] = Node{
sum: val,
max_pref: val,
min_pref: val,
max_suff: val,
min_suff: val,
}
return
}
mid := l + (r-l)/2
if idx <= mid {
update(node*2, l, mid, idx, val)
} else {
update(node*2+1, mid+1, r, idx, val)
}
tree[node] = merge(tree[node*2], tree[node*2+1])
}
func query(node, l, r, ql, qr int) Node {
if ql <= l && r <= qr {
return tree[node]
}
mid := l + (r-l)/2
if qr <= mid {
return query(node*2, l, mid, ql, qr)
}
if ql > mid {
return query(node*2+1, mid+1, r, ql, qr)
}
return merge(
query(node*2, l, mid, ql, qr),
query(node*2+1, mid+1, r, ql, qr),
)
}
func main() {
scanner := bufio.NewScanner(os.Stdin)
buf := make([]byte, 1024*1024)
scanner.Buffer(buf, 1024*1024)
scanner.Split(bufio.ScanWords)
if !scanner.Scan() {
return
}
n, _ := strconv.Atoi(scanner.Text())
a := make([]int, n+1)
pos := make([][]int, n+1)
for i := 1; i <= n; i++ {
scanner.Scan()
a[i], _ = strconv.Atoi(scanner.Text())
pos[a[i]] = append(pos[a[i]], i)
}
tree = make([]Node, 4*n+1)
if n > 0 {
build(1, 1, n)
}
ans := make([]int, n+1)
for v := 1; v <= n; v++ {
if len(pos[v]) == 0 {
continue
}
for _, i := range pos[v] {
leftNode := query(1, 1, n, 1, i)
rightNode := query(1, 1, n, i, n)
sPrime := -leftNode.min_suff - rightNode.min_pref - 1
if sPrime > 0 {
cand := sPrime / 2
if cand > ans[i] {
ans[i] = cand
}
}
}
for _, i := range pos[v] {
update(1, 1, n, i, 1)
}
for _, i := range pos[v] {
leftNode := query(1, 1, n, 1, i)
rightNode := query(1, 1, n, i, n)
s := leftNode.max_suff + rightNode.max_pref - 1
if s-1 > 0 {
cand := (s - 1) / 2
if cand > ans[i] {
ans[i] = cand
}
}
}
}
out := make([]string, n)
for i := 1; i <= n; i++ {
out[i-1] = strconv.Itoa(ans[i])
}
fmt.Println(strings.Join(out, " "))
}