package main
import (
"bufio"
"fmt"
"math/bits"
"math/rand"
"os"
"time"
)
var (
in *bufio.Reader
out *bufio.Writer
n int
cache []int16
)
func pos(i, j int) int {
return i*n + j
}
func ask(i, j int) int {
if i == j {
return 0
}
p := pos(i, j)
if cache[p] != -1 {
return int(cache[p])
}
fmt.Fprintf(out, "? %d %d\n", i+1, j+1)
out.Flush()
var x int
fmt.Fscan(in, &x)
if x < 0 {
os.Exit(0)
}
cache[pos(i, j)] = int16(x)
cache[pos(j, i)] = int16(x)
return x
}
func chooseStart() int {
s := 15
if n < s {
s = n
}
sample := rand.Perm(n)[:s]
for i := 0; i < s; i++ {
for j := i + 1; j < s; j++ {
ask(sample[i], sample[j])
}
}
best := sample[0]
bestPop := 1 << 30
for _, v := range sample {
mask := 0
for b := 0; b < 11; b++ {
bit := 1 << b
ok := true
for _, u := range sample {
if u == v {
continue
}
if ask(v, u)&bit == 0 {
ok = false
break
}
}
if ok {
mask |= bit
}
}
pc := bits.OnesCount(uint(mask))
if pc < bestPop {
bestPop = pc
best = v
}
}
return best
}
func findZero(start int) (int, bool, []int) {
set := make([]int, n)
for i := 0; i < n; i++ {
set[i] = i
}
cur := start
minPos := 1
for {
if len(set) == 1 {
return set[0], false, nil
}
mn := 1 << 30
eq := make([]int, 0)
ans := make(map[int]int, len(set)-1)
for _, v := range set {
if v == cur {
continue
}
x := ask(cur, v)
ans[v] = x
if x < mn {
mn = x
eq = eq[:0]
eq = append(eq, v)
} else if x == mn {
eq = append(eq, v)
}
}
if mn == minPos {
other := eq[0]
zero := other
for _, v := range set {
if v == cur || v == other {
continue
}
if ans[v]&minPos == 0 {
zero = cur
break
}
}
if zero == cur && len(set) == n {
p := make([]int, n)
p[cur] = 0
for idx, val := range ans {
p[idx] = val
}
return zero, true, p
}
return zero, false, nil
}
if len(eq) == 1 {
return eq[0], false, nil
}
next := make([]int, len(eq))
copy(next, eq)
set = next
cur = set[rand.Intn(len(set))]
minPos = mn & -mn
}
}
func reconstruct(z int) []int {
p := make([]int, n)
p[z] = 0
for i := 0; i < n; i++ {
if i == z {
continue
}
p[i] = ask(z, i)
}
return p
}
func main() {
in = bufio.NewReader(os.Stdin)
out = bufio.NewWriter(os.Stdout)
defer out.Flush()
fmt.Fscan(in, &n)
cache = make([]int16, n*n)
for i := range cache {
cache[i] = -1
}
rand.Seed(time.Now().UnixNano())
start := chooseStart()
zero, known, p := findZero(start)
if !known {
p = reconstruct(zero)
}
fmt.Fprint(out, "!")
for i := 0; i < n; i++ {
fmt.Fprintf(out, " %d", p[i])
}
fmt.Fprintln(out)
out.Flush()
}