```go
package main
import (
"bufio"
"fmt"
"os"
"sort"
"strconv"
)
type Wizard struct {
id int
a int
}
func main() {
scanner := bufio.NewScanner(os.Stdin)
scanner.Split(bufio.ScanWords)
scanner.Scan()
n, _ := strconv.Atoi(scanner.Text())
wizards := make([]Wizard, n)
for i := 0; i < n; i++ {
scanner.Scan()
val, _ := strconv.Atoi(scanner.Text())
wizards[i] = Wizard{id: i, a: val}
}
// Separate into Restricted (a > n/2) and Unrestricted
var restricted []Wizard
var unrestricted []Wizard
for _, w := range wizards {
if w.a > n/2 {
restricted = append(restricted, w)
} else {
unrestricted = append(unrestricted, w)
}
}
// Sort restricted by a descending
sort.Slice(restricted, func(i, j int) bool {
return restricted[i].a > restricted[j].a
})
ansX := make([]int, n) // stores x-coordinate for wizard i (0-indexed)
// Greedy allocation for x-coordinates
// Treat a=n as a=n-1 for allocation purposes
L, R := 1, n
for _, w := range restricted {
val := w.a
effVal := val
if val == n {
effVal = n - 1
}
if L <= n-effVal {
ansX[w.id] = L
L++
} else if R > effVal {
ansX[w.id] = R
R--
} else {
fmt.Println("NO")
return
}
}
for _, w := range unrestricted {
ansX[w.id] = L
L++
}
// Position map: x -> wizard_id
posToWiz := make([]int, n+1)
for i := 0; i < n; i++ {
posToWiz[ansX[i]] = i
}
// Try two configurations for y-coordinates to handle a=n
// Config 1: if a=n and x=1, y=2; else y=1
// Config 2: if a=n and x=n, y=2; else y=1
configs := []int{1, 2}
finalY := make([]int, n)
finalTarget := make([]int, n)
success := false
for _, cfg := range configs {
currentY := make([]int, n)
currentTarget := make([]int, n)
possible := true
for i := 0; i < n; i++ {
if wizards[i].a == n {
if cfg == 1 && ansX[i] == 1 {
currentY[i] = 2
} else if cfg == 2 && ansX[i] == n {
currentY[i] = 2
} else {
currentY[i] = 1
}
} else {
currentY[i] = 1
}
}
for i := 0; i < n; i++ {
req := wizards[i].a
x := ansX[i]
y := currentY[i]
found := false
// Check candidates x-req and x+req (if req=n, candidates are outside range usually,
// but for a=n we rely on y-diff, so we check x-(n-1) and x+(n-1) logic isn't strictly applicable directly.
// Actually, we should just check all x that are 'req' distance away in X OR valid candidates.
// For a=n, x-dist is n-1. For a<n, x-dist is a.
// Candidates based on 1D projection:
// If a < n, candidate x's are x-a, x+a.
// If a = n, candidate x's are x-(n-1), x+(n-1) (corners).
distsToCheck := []int{req}
if req == n {
distsToCheck = []int{n-1}
}
for _, d := range distsToCheck {
cands := []int{x - d, x + d}
for _, cx := range cands {
if cx >= 1 && cx <= n {
targetID := posToWiz[cx]
ty := currentY[targetID]
dist := abs(x-cx) + abs(y-ty)
if dist == req {
currentTarget[i] = targetID + 1 // 1-based index
found = true
break
}
}
}
if found {
break
}
}
if !found {
possible = false
break
}
}
if possible {
copy(finalY, currentY)
copy(finalTarget, currentTarget)
success = true
break
}
}
if success {
fmt.Println("YES")
for i := 0; i < n; i++ {
fmt.Printf("%d %d\n", ansX[i], finalY[i])
}
for i := 0; i < n; i++ {
if i > 0 {
fmt.Print(" ")
}
fmt.Print(finalTarget[i])
}
fmt.Println()
} else {
fmt.Println("NO")
}
}
func abs(x int) int {
if x < 0 {
return -x
}
return x
}
```