/*
二分探索木が極端に片寄った形になったら、もっと性能の良い形、即ち左右の
バランスの取れた形に直す。このような木を平衡木(balanced tree)と呼ぶ。
木の作り直しはレコード(頂点)の挿入や削除の際に行われる。
その計算量がO(n)を超えるようならば、列の二分探索で十分であり、
平衡木を採用する意味がない。
従って、作り直しの計算量はO(log2(n))以下に抑えたい。
この観点から、常に完全二分木を保つのは望ましくない。ほどほどで良い。
片寄り方に限度を設けるため、次の制約を持つ二分探索木を、AVL-treeと呼ぶ。
制約:どの頂点においても、その左部分木の高さと右部分木の高さの差が
+1,0,-1のいずれかでなければならない。
*/
package main
import (
"fmt"
)
// AVL木(の頂点)。
// 同じ木の中でkeyは一意であること。
// 平衡係数の初期値は0。左部分木の方が高いほど+1、右部分木の方が高いほど-1する。
// 平衡係数が2以上または-2以下の頂点が出来たとき木を再構成する。
type btree struct {
key int
value string
left *btree
right *btree
balance int // 平衡係数
}
// 探索。木tの中でキーがkeyと一致する頂点のvalueを返す。
// そのような頂点が見つからなかった場合は空文字列を返す。
func search(t *btree, key int) string {
switch {
case t == nil:
return ""
case t.key < key:
return search(t.right, key)
case key < t.key:
return search(t.left, key)
}
return t.value
}
// 木tの適切な位置に新しい頂点を挿入した木を返す。
// valueに空文字列は使わないこと
func insert(t *btree, key int, value string) *btree {
t, _ = insertAux(t, key, value)
return t
}
// 木tの適切な位置に新しい頂点を挿入した木を返す。
// また、木の高さが増えたかどうかのフラグも返す。
func insertAux(t *btree, key int, value string) (*btree, bool) {
var gu bool // 木の高さが増えたらtrue
switch {
case t == nil:
t = &btree{key: key, value: value, balance: 0}
gu = true
case key < t.key:
t.left, gu = insertAux(t.left, key, value)
if gu {
t.balance++
if t.balance < 2 {
gu = !(t.balance == 0) // 平衡になったということは、高さが増えてないということ
} else if 0 < t.left.balance {
t, gu = leftSingleRotation(t), false
} else {
t, gu = leftDoubleRotation(t), false
}
}
case t.key < key:
t.right, gu = insertAux(t.right, key, value)
if gu {
t.balance--
if -2 < t.balance {
gu = !(t.balance == 0)
} else if t.right.balance < 0 {
t, gu = rightSingleRotation(t), false
} else {
t, gu = rightDoubleRotation(t), false
}
}
}
return t, gu
}
// 木tからkeyを持つ頂点を削除した木を返す。
func
remove(t
*btree
, key
int) *btree
{ t, _ = removeAux(t, key)
return t
}
// 木tからkeyを持つ頂点を削除した木を返す。
// また、木の高さが減ったかどうかのフラグも返す。
func removeAux(t *btree, key int) (*btree, bool) {
var su bool // 木の高さが減ったらtrue
switch {
case t == nil:
su = false
case key < t.key:
t.left, su = removeAux(t.left, key)
if su {
t.balance--
if -2 < t.balance {
su = (t.balance == 0) // 平衡になったということは、高さが減ったということ
} else if t.right.balance < 0 {
t, su = rightSingleRotation(t), true
} else {
t, su = rightDoubleRotation(t), true
}
}
case t.key < key:
t.right, su = removeAux(t.right, key)
if su {
t.balance++
if t.balance < 2 {
su = (t.balance == 0)
} else if 0 < t.left.balance {
t, su = leftSingleRotation(t), true
} else {
t, su = leftDoubleRotation(t), true
}
}
default:
t, su = removeRoot(t), true
}
return t, su
}
// 根tが表す木からtを削除して返す。
func removeRoot(t *btree) *btree {
// 左子が無いなら右子を持ちあげるだけ
if t.left == nil {
return t.right
}
// 左子の右子がないということは、左子はtの次に大きい頂点である
if t.left.right == nil {
l := t.left
l.right = t.right
l.recalcBalance()
return l
}
// まずtの次の次に大きい頂点pを探しだして
var p *btree
for p = t.left; p.right.right != nil; p = p.right {
}
// tの次に大きい頂点sを新しい根とする
s := p.right
p.right = s.left
p.recalcBalance()
s.left = t.left
s.right = t.right
s.recalcBalance()
return s
}
// 頂点tが左に、かつその左部分木が左に片寄っている場合、
// 一重回転してt.leftを根にする。
func leftSingleRotation(t *btree) *btree {
l := t.left
t.left = l.right
l.right = t
t.recalcBalance()
l.recalcBalance()
return l
}
// 頂点tが左に、かつその左部分木が右に片寄っている場合、
// 二重回転してt.leftの子を根にする。
func leftDoubleRotation(t *btree) *btree {
l := t.left
lr := l.right
if lr.right != nil {
l.right = nil
} else {
l.right = lr.left
}
lr.left = l
l.recalcBalance()
t.left = lr
return leftSingleRotation(t)
}
// 頂点tが右に、かつその右部分木が右に片寄っている場合、
// 一重回転してt.rightを根にする。
func rightSingleRotation(t *btree) *btree {
r := t.right
t.right = r.left
r.left = t
t.recalcBalance()
r.recalcBalance()
return r
}
// 頂点tが右に、かつその右部分木が左に片寄っている場合、
// 二重回転してt.rightの子を根にする。
func rightDoubleRotation(t *btree) *btree {
r := t.right
rr := r.left
if rr.left != nil {
r.left = nil
} else {
r.left = rr.right
}
rr.right = r
r.recalcBalance()
t.right = rr
return rightSingleRotation(t)
}
// 平衡係数を再計算する。
func (t *btree) recalcBalance() {
switch {
case t.left == nil && t.right == nil:
t.balance = 0
case t.right == nil:
t.balance = 1
case t.left == nil:
t.balance = -1
default:
lgc := t.left.left != nil || t.left.right != nil // 左の孫を持つならtrue
rgc := t.right.left != nil || t.right.right != nil // 右の孫を持つならtrue
switch {
case lgc && !rgc:
t.balance = 1
case !lgc && rgc:
t.balance = -1
default:
t.balance = 0
}
}
}
// 頂点のkey兼valueとしたい0個以上の整数を受け取り、tを生成して返す
func buildTree(keys []int) *btree {
var t *btree
for _, k := range keys {
t = insert(t, k, fmt.Sprint(k))
}
return t
}
// 木tの各頂点の値と平行係数を表示する
func pt(t *btree) {
dq := make([]*btree, 0, 100) // 同じ深さの節を保持するキュー
bf := make([]*btree, 0, 100) // dqに追加予定の節を一時保存するキュー
bf = append(bf, t)
// 同じ深さの節を全て表示したら、次の深さの節の処理に移ることの繰り返し
var e *btree
for allIsNil(bf) == false {
dq = append(dq, bf...)
bf = bf[len(bf):]
for 0 < len(dq) {
e, dq = dq[0], dq[1:]
if e != nil {
fmt.Printf("[%v:%v] ", e.value, e.balance)
bf = append(bf, e.left)
bf = append(bf, e.right)
} else {
fmt.Printf("[_:_] ")
bf = append(bf, nil)
bf = append(bf, nil)
}
}
fmt.Println()
}
fmt.Println()
}
// xsの全要素がnilであるときtrueを返す
func allIsNil(xs []*btree) bool {
res := true
for _, x := range xs {
res = (res && x == nil)
}
return res
}
func main() {
var t *btree
t = buildTree([]int{50, 30, 70, 20, 40, 60, 80, 25, 55, 65, 75, 85, 90})
pt(t)
fmt.Println("---- キー20を削除して構造の変化を見てみる")
pt(t)
}
LyoK5LqM5YiG5o6i57Si5pyo44GM5qW156uv44Gr54mH5a+E44Gj44Gf5b2i44Gr44Gq44Gj44Gf44KJ44CB44KC44Gj44Go5oCn6IO944Gu6Imv44GE5b2i44CB5Y2z44Gh5bem5Y+z44GuCuODkOODqeODs+OCueOBruWPluOCjOOBn+W9ouOBq+ebtOOBmeOAguOBk+OBruOCiOOBhuOBquacqOOCkuW5s+ihoeacqChiYWxhbmNlZCB0cmVlKeOBqOWRvOOBtuOAggoK5pyo44Gu5L2c44KK55u044GX44Gv44Os44Kz44O844OJKOmggueCuSnjga7mjL/lhaXjgoTliYrpmaTjga7pmpvjgavooYzjgo/jgozjgovjgIIK44Gd44Gu6KiI566X6YeP44GMTyhuKeOCkui2heOBiOOCi+OCiOOBhuOBquOCieOBsOOAgeWIl+OBruS6jOWIhuaOoue0ouOBp+WNgeWIhuOBp+OBguOCiuOAgQrlubPooaHmnKjjgpLmjqHnlKjjgZnjgovmhI/lkbPjgYzjgarjgYTjgIIK5b6T44Gj44Gm44CB5L2c44KK55u044GX44Gu6KiI566X6YeP44GvTyhsb2cyKG4pKeS7peS4i+OBq+aKkeOBiOOBn+OBhOOAggrjgZPjga7oprPngrnjgYvjgonjgIHluLjjgavlrozlhajkuozliIbmnKjjgpLkv53jgaTjga7jga/mnJvjgb7jgZfjgY/jgarjgYTjgILjgbvjganjgbvjganjgafoia/jgYTjgIIKCueJh+WvhOOCiuaWueOBq+mZkOW6puOCkuioreOBkeOCi+OBn+OCgeOAgeasoeOBruWItue0hOOCkuaMgeOBpOS6jOWIhuaOoue0ouacqOOCkuOAgUFWTC10cmVl44Go5ZG844G244CCCuWItue0hO+8muOBqeOBrumggueCueOBq+OBiuOBhOOBpuOCguOAgeOBneOBruW3pumDqOWIhuacqOOBrumrmOOBleOBqOWPs+mDqOWIhuacqOOBrumrmOOBleOBruW3ruOBjAorMSwwLC0x44Gu44GE44Ga44KM44GL44Gn44Gq44GR44KM44Gw44Gq44KJ44Gq44GE44CCCiovCnBhY2thZ2UgbWFpbgoKaW1wb3J0ICgKCSJmbXQiCikKCi8vIEFWTOacqCjjga7poILngrkp44CCCi8vIOWQjOOBmOacqOOBruS4reOBp2tleeOBr+S4gOaEj+OBp+OBguOCi+OBk+OBqOOAggovLyDlubPooaHkv4LmlbDjga7liJ3mnJ/lgKTjga8w44CC5bem6YOo5YiG5pyo44Gu5pa544GM6auY44GE44G744GpKzHjgIHlj7Ppg6jliIbmnKjjga7mlrnjgYzpq5jjgYTjgbvjgaktMeOBmeOCi+OAggovLyDlubPooaHkv4LmlbDjgYwy5Lul5LiK44G+44Gf44GvLTLku6XkuIvjga7poILngrnjgYzlh7rmnaXjgZ/jgajjgY3mnKjjgpLlho3mp4vmiJDjgZnjgovjgIIKdHlwZSBidHJlZSBzdHJ1Y3QgewoJa2V5ICAgICBpbnQKCXZhbHVlICAgc3RyaW5nCglsZWZ0ICAgICpidHJlZQoJcmlnaHQgICAqYnRyZWUKCWJhbGFuY2UgaW50IC8vIOW5s+ihoeS/guaVsAp9CgovLyDmjqLntKLjgILmnKh044Gu5Lit44Gn44Kt44O844GMa2V544Go5LiA6Ie044GZ44KL6aCC54K544GudmFsdWXjgpLov5TjgZnjgIIKLy8g44Gd44Gu44KI44GG44Gq6aCC54K544GM6KaL44Gk44GL44KJ44Gq44GL44Gj44Gf5aC05ZCI44Gv56m65paH5a2X5YiX44KS6L+U44GZ44CCCmZ1bmMgc2VhcmNoKHQgKmJ0cmVlLCBrZXkgaW50KSBzdHJpbmcgewoJc3dpdGNoIHsKCWNhc2UgdCA9PSBuaWw6CgkJcmV0dXJuICIiCgljYXNlIHQua2V5IDwga2V5OgoJCXJldHVybiBzZWFyY2godC5yaWdodCwga2V5KQoJY2FzZSBrZXkgPCB0LmtleToKCQlyZXR1cm4gc2VhcmNoKHQubGVmdCwga2V5KQoJfQoJcmV0dXJuIHQudmFsdWUKfQoKLy8g5pyodOOBrumBqeWIh+OBquS9jee9ruOBq+aWsOOBl+OBhOmggueCueOCkuaMv+WFpeOBl+OBn+acqOOCkui/lOOBmeOAggovLyB2YWx1ZeOBq+epuuaWh+Wtl+WIl+OBr+S9v+OCj+OBquOBhOOBk+OBqApmdW5jIGluc2VydCh0ICpidHJlZSwga2V5IGludCwgdmFsdWUgc3RyaW5nKSAqYnRyZWUgewoJdCwgXyA9IGluc2VydEF1eCh0LCBrZXksIHZhbHVlKQoJcmV0dXJuIHQKfQoKLy8g5pyodOOBrumBqeWIh+OBquS9jee9ruOBq+aWsOOBl+OBhOmggueCueOCkuaMv+WFpeOBl+OBn+acqOOCkui/lOOBmeOAggovLyDjgb7jgZ/jgIHmnKjjga7pq5jjgZXjgYzlopfjgYjjgZ/jgYvjganjgYbjgYvjga7jg5Xjg6njgrDjgoLov5TjgZnjgIIKZnVuYyBpbnNlcnRBdXgodCAqYnRyZWUsIGtleSBpbnQsIHZhbHVlIHN0cmluZykgKCpidHJlZSwgYm9vbCkgewoJdmFyIGd1IGJvb2wgLy8g5pyo44Gu6auY44GV44GM5aKX44GI44Gf44KJdHJ1ZQoJc3dpdGNoIHsKCWNhc2UgdCA9PSBuaWw6CgkJdCA9ICZidHJlZXtrZXk6IGtleSwgdmFsdWU6IHZhbHVlLCBiYWxhbmNlOiAwfQoJCWd1ID0gdHJ1ZQoJY2FzZSBrZXkgPCB0LmtleToKCQl0LmxlZnQsIGd1ID0gaW5zZXJ0QXV4KHQubGVmdCwga2V5LCB2YWx1ZSkKCQlpZiBndSB7CgkJCXQuYmFsYW5jZSsrCgkJCWlmIHQuYmFsYW5jZSA8IDIgewoJCQkJZ3UgPSAhKHQuYmFsYW5jZSA9PSAwKSAvLyDlubPooaHjgavjgarjgaPjgZ/jgajjgYTjgYbjgZPjgajjga/jgIHpq5jjgZXjgYzlopfjgYjjgabjgarjgYTjgajjgYTjgYbjgZPjgagKCQkJfSBlbHNlIGlmIDAgPCB0LmxlZnQuYmFsYW5jZSB7CgkJCQl0LCBndSA9IGxlZnRTaW5nbGVSb3RhdGlvbih0KSwgZmFsc2UKCQkJfSBlbHNlIHsKCQkJCXQsIGd1ID0gbGVmdERvdWJsZVJvdGF0aW9uKHQpLCBmYWxzZQoJCQl9CgkJfQoJY2FzZSB0LmtleSA8IGtleToKCQl0LnJpZ2h0LCBndSA9IGluc2VydEF1eCh0LnJpZ2h0LCBrZXksIHZhbHVlKQoJCWlmIGd1IHsKCQkJdC5iYWxhbmNlLS0KCQkJaWYgLTIgPCB0LmJhbGFuY2UgewoJCQkJZ3UgPSAhKHQuYmFsYW5jZSA9PSAwKQoJCQl9IGVsc2UgaWYgdC5yaWdodC5iYWxhbmNlIDwgMCB7CgkJCQl0LCBndSA9IHJpZ2h0U2luZ2xlUm90YXRpb24odCksIGZhbHNlCgkJCX0gZWxzZSB7CgkJCQl0LCBndSA9IHJpZ2h0RG91YmxlUm90YXRpb24odCksIGZhbHNlCgkJCX0KCQl9Cgl9CglyZXR1cm4gdCwgZ3UKfQoKLy8g5pyodOOBi+OCiWtleeOCkuaMgeOBpOmggueCueOCkuWJiumZpOOBl+OBn+acqOOCkui/lOOBmeOAggpmdW5jIHJlbW92ZSh0ICpidHJlZSwga2V5IGludCkgKmJ0cmVlIHsKCXQsIF8gPSByZW1vdmVBdXgodCwga2V5KQoJcmV0dXJuIHQKfQoKLy8g5pyodOOBi+OCiWtleeOCkuaMgeOBpOmggueCueOCkuWJiumZpOOBl+OBn+acqOOCkui/lOOBmeOAggovLyDjgb7jgZ/jgIHmnKjjga7pq5jjgZXjgYzmuJvjgaPjgZ/jgYvjganjgYbjgYvjga7jg5Xjg6njgrDjgoLov5TjgZnjgIIKZnVuYyByZW1vdmVBdXgodCAqYnRyZWUsIGtleSBpbnQpICgqYnRyZWUsIGJvb2wpIHsKCXZhciBzdSBib29sIC8vIOacqOOBrumrmOOBleOBjOa4m+OBo+OBn+OCiXRydWUKCXN3aXRjaCB7CgljYXNlIHQgPT0gbmlsOgoJCXN1ID0gZmFsc2UKCWNhc2Uga2V5IDwgdC5rZXk6CgkJdC5sZWZ0LCBzdSA9IHJlbW92ZUF1eCh0LmxlZnQsIGtleSkKCQlpZiBzdSB7CgkJCXQuYmFsYW5jZS0tCgkJCWlmIC0yIDwgdC5iYWxhbmNlIHsKCQkJCXN1ID0gKHQuYmFsYW5jZSA9PSAwKSAvLyDlubPooaHjgavjgarjgaPjgZ/jgajjgYTjgYbjgZPjgajjga/jgIHpq5jjgZXjgYzmuJvjgaPjgZ/jgajjgYTjgYbjgZPjgagKCQkJfSBlbHNlIGlmIHQucmlnaHQuYmFsYW5jZSA8IDAgewoJCQkJdCwgc3UgPSByaWdodFNpbmdsZVJvdGF0aW9uKHQpLCB0cnVlCgkJCX0gZWxzZSB7CgkJCQl0LCBzdSA9IHJpZ2h0RG91YmxlUm90YXRpb24odCksIHRydWUKCQkJfQoJCX0KCWNhc2UgdC5rZXkgPCBrZXk6CgkJdC5yaWdodCwgc3UgPSByZW1vdmVBdXgodC5yaWdodCwga2V5KQoJCWlmIHN1IHsKCQkJdC5iYWxhbmNlKysKCQkJaWYgdC5iYWxhbmNlIDwgMiB7CgkJCQlzdSA9ICh0LmJhbGFuY2UgPT0gMCkKCQkJfSBlbHNlIGlmIDAgPCB0LmxlZnQuYmFsYW5jZSB7CgkJCQl0LCBzdSA9IGxlZnRTaW5nbGVSb3RhdGlvbih0KSwgdHJ1ZQoJCQl9IGVsc2UgewoJCQkJdCwgc3UgPSBsZWZ0RG91YmxlUm90YXRpb24odCksIHRydWUKCQkJfQoJCX0KCWRlZmF1bHQ6CgkJdCwgc3UgPSByZW1vdmVSb290KHQpLCB0cnVlCgl9CglyZXR1cm4gdCwgc3UKfQoKLy8g5qC5dOOBjOihqOOBmeacqOOBi+OCiXTjgpLliYrpmaTjgZfjgabov5TjgZnjgIIKZnVuYyByZW1vdmVSb290KHQgKmJ0cmVlKSAqYnRyZWUgewoJLy8g5bem5a2Q44GM54Sh44GE44Gq44KJ5Y+z5a2Q44KS5oyB44Gh44GC44GS44KL44Gg44GRCglpZiB0LmxlZnQgPT0gbmlsIHsKCQlyZXR1cm4gdC5yaWdodAoJfQoJLy8g5bem5a2Q44Gu5Y+z5a2Q44GM44Gq44GE44Go44GE44GG44GT44Go44Gv44CB5bem5a2Q44GvdOOBruasoeOBq+Wkp+OBjeOBhOmggueCueOBp+OBguOCiwoJaWYgdC5sZWZ0LnJpZ2h0ID09IG5pbCB7CgkJbCA6PSB0LmxlZnQKCQlsLnJpZ2h0ID0gdC5yaWdodAoJCWwucmVjYWxjQmFsYW5jZSgpCgkJcmV0dXJuIGwKCX0KCS8vIOOBvuOBmnTjga7mrKHjga7mrKHjgavlpKfjgY3jgYTpoILngrlw44KS5o6i44GX44Gg44GX44GmCgl2YXIgcCAqYnRyZWUKCWZvciBwID0gdC5sZWZ0OyBwLnJpZ2h0LnJpZ2h0ICE9IG5pbDsgcCA9IHAucmlnaHQgewoJfQoJLy8gdOOBruasoeOBq+Wkp+OBjeOBhOmggueCuXPjgpLmlrDjgZfjgYTmoLnjgajjgZnjgosKCXMgOj0gcC5yaWdodAoJcC5yaWdodCA9IHMubGVmdAoJcC5yZWNhbGNCYWxhbmNlKCkKCXMubGVmdCA9IHQubGVmdAoJcy5yaWdodCA9IHQucmlnaHQKCXMucmVjYWxjQmFsYW5jZSgpCglyZXR1cm4gcwp9CgovLyDpoILngrl044GM5bem44Gr44CB44GL44Gk44Gd44Gu5bem6YOo5YiG5pyo44GM5bem44Gr54mH5a+E44Gj44Gm44GE44KL5aC05ZCI44CBCi8vIOS4gOmHjeWbnui7ouOBl+OBpnQubGVmdOOCkuagueOBq+OBmeOCi+OAggpmdW5jIGxlZnRTaW5nbGVSb3RhdGlvbih0ICpidHJlZSkgKmJ0cmVlIHsKCWwgOj0gdC5sZWZ0Cgl0LmxlZnQgPSBsLnJpZ2h0CglsLnJpZ2h0ID0gdAoJdC5yZWNhbGNCYWxhbmNlKCkKCWwucmVjYWxjQmFsYW5jZSgpCglyZXR1cm4gbAp9CgovLyDpoILngrl044GM5bem44Gr44CB44GL44Gk44Gd44Gu5bem6YOo5YiG5pyo44GM5Y+z44Gr54mH5a+E44Gj44Gm44GE44KL5aC05ZCI44CBCi8vIOS6jOmHjeWbnui7ouOBl+OBpnQubGVmdOOBruWtkOOCkuagueOBq+OBmeOCi+OAggpmdW5jIGxlZnREb3VibGVSb3RhdGlvbih0ICpidHJlZSkgKmJ0cmVlIHsKCWwgOj0gdC5sZWZ0CglsciA6PSBsLnJpZ2h0CglpZiBsci5yaWdodCAhPSBuaWwgewoJCWwucmlnaHQgPSBuaWwKCX0gZWxzZSB7CgkJbC5yaWdodCA9IGxyLmxlZnQKCX0KCWxyLmxlZnQgPSBsCglsLnJlY2FsY0JhbGFuY2UoKQoJdC5sZWZ0ID0gbHIKCXJldHVybiBsZWZ0U2luZ2xlUm90YXRpb24odCkKfQoKLy8g6aCC54K5dOOBjOWPs+OBq+OAgeOBi+OBpOOBneOBruWPs+mDqOWIhuacqOOBjOWPs+OBq+eJh+WvhOOBo+OBpuOBhOOCi+WgtOWQiOOAgQovLyDkuIDph43lm57ou6LjgZfjgaZ0LnJpZ2h044KS5qC544Gr44GZ44KL44CCCmZ1bmMgcmlnaHRTaW5nbGVSb3RhdGlvbih0ICpidHJlZSkgKmJ0cmVlIHsKCXIgOj0gdC5yaWdodAoJdC5yaWdodCA9IHIubGVmdAoJci5sZWZ0ID0gdAoJdC5yZWNhbGNCYWxhbmNlKCkKCXIucmVjYWxjQmFsYW5jZSgpCglyZXR1cm4gcgp9CgovLyDpoILngrl044GM5Y+z44Gr44CB44GL44Gk44Gd44Gu5Y+z6YOo5YiG5pyo44GM5bem44Gr54mH5a+E44Gj44Gm44GE44KL5aC05ZCI44CBCi8vIOS6jOmHjeWbnui7ouOBl+OBpnQucmlnaHTjga7lrZDjgpLmoLnjgavjgZnjgovjgIIKZnVuYyByaWdodERvdWJsZVJvdGF0aW9uKHQgKmJ0cmVlKSAqYnRyZWUgewoJciA6PSB0LnJpZ2h0CglyciA6PSByLmxlZnQKCWlmIHJyLmxlZnQgIT0gbmlsIHsKCQlyLmxlZnQgPSBuaWwKCX0gZWxzZSB7CgkJci5sZWZ0ID0gcnIucmlnaHQKCX0KCXJyLnJpZ2h0ID0gcgoJci5yZWNhbGNCYWxhbmNlKCkKCXQucmlnaHQgPSBycgoJcmV0dXJuIHJpZ2h0U2luZ2xlUm90YXRpb24odCkKfQoKLy8g5bmz6KGh5L+C5pWw44KS5YaN6KiI566X44GZ44KL44CCCmZ1bmMgKHQgKmJ0cmVlKSByZWNhbGNCYWxhbmNlKCkgewoJc3dpdGNoIHsKCWNhc2UgdC5sZWZ0ID09IG5pbCAmJiB0LnJpZ2h0ID09IG5pbDoKCQl0LmJhbGFuY2UgPSAwCgljYXNlIHQucmlnaHQgPT0gbmlsOgoJCXQuYmFsYW5jZSA9IDEKCWNhc2UgdC5sZWZ0ID09IG5pbDoKCQl0LmJhbGFuY2UgPSAtMQoJZGVmYXVsdDoKCQlsZ2MgOj0gdC5sZWZ0LmxlZnQgIT0gbmlsIHx8IHQubGVmdC5yaWdodCAhPSBuaWwgICAvLyDlt6bjga7lravjgpLmjIHjgaTjgarjgol0cnVlCgkJcmdjIDo9IHQucmlnaHQubGVmdCAhPSBuaWwgfHwgdC5yaWdodC5yaWdodCAhPSBuaWwgLy8g5Y+z44Gu5a2r44KS5oyB44Gk44Gq44KJdHJ1ZQoJCXN3aXRjaCB7CgkJY2FzZSBsZ2MgJiYgIXJnYzoKCQkJdC5iYWxhbmNlID0gMQoJCWNhc2UgIWxnYyAmJiByZ2M6CgkJCXQuYmFsYW5jZSA9IC0xCgkJZGVmYXVsdDoKCQkJdC5iYWxhbmNlID0gMAoJCX0KCX0KfQoKCgovLyDpoILngrnjga5rZXnlhbx2YWx1ZeOBqOOBl+OBn+OBhDDlgIvku6XkuIrjga7mlbTmlbDjgpLlj5fjgZHlj5bjgorjgIF044KS55Sf5oiQ44GX44Gm6L+U44GZCmZ1bmMgYnVpbGRUcmVlKGtleXMgW11pbnQpICpidHJlZSB7Cgl2YXIgdCAqYnRyZWUKCWZvciBfLCBrIDo9IHJhbmdlIGtleXMgewoJCXQgPSBpbnNlcnQodCwgaywgZm10LlNwcmludChrKSkKCX0KCXJldHVybiB0Cn0KCi8vIOacqHTjga7lkITpoILngrnjga7lgKTjgajlubPooYzkv4LmlbDjgpLooajnpLrjgZnjgosKZnVuYyBwdCh0ICpidHJlZSkgewoJZHEgOj0gbWFrZShbXSpidHJlZSwgMCwgMTAwKSAvLyDlkIzjgZjmt7HjgZXjga7nr4DjgpLkv53mjIHjgZnjgovjgq3jg6Xjg7wKCWJmIDo9IG1ha2UoW10qYnRyZWUsIDAsIDEwMCkgLy8gZHHjgavov73liqDkuojlrprjga7nr4DjgpLkuIDmmYLkv53lrZjjgZnjgovjgq3jg6Xjg7wKCWJmID0gYXBwZW5kKGJmLCB0KQoJLy8g5ZCM44GY5rex44GV44Gu56+A44KS5YWo44Gm6KGo56S644GX44Gf44KJ44CB5qyh44Gu5rex44GV44Gu56+A44Gu5Yem55CG44Gr56e744KL44GT44Go44Gu57mw44KK6L+U44GXCgl2YXIgZSAqYnRyZWUKCWZvciBhbGxJc05pbChiZikgPT0gZmFsc2UgewoJCWRxID0gYXBwZW5kKGRxLCBiZi4uLikKCQliZiA9IGJmW2xlbihiZik6XQoJCWZvciAwIDwgbGVuKGRxKSB7CgkJCWUsIGRxID0gZHFbMF0sIGRxWzE6XQoJCQlpZiBlICE9IG5pbCB7CgkJCQlmbXQuUHJpbnRmKCJbJXY6JXZdICIsIGUudmFsdWUsIGUuYmFsYW5jZSkKCQkJCWJmID0gYXBwZW5kKGJmLCBlLmxlZnQpCgkJCQliZiA9IGFwcGVuZChiZiwgZS5yaWdodCkKCQkJfSBlbHNlIHsKCQkJCWZtdC5QcmludGYoIltfOl9dICIpCgkJCQliZiA9IGFwcGVuZChiZiwgbmlsKQoJCQkJYmYgPSBhcHBlbmQoYmYsIG5pbCkKCQkJfQoJCX0KCQlmbXQuUHJpbnRsbigpCgl9CglmbXQuUHJpbnRsbigpCn0KCi8vIHhz44Gu5YWo6KaB57Sg44GMbmls44Gn44GC44KL44Go44GNdHJ1ZeOCkui/lOOBmQpmdW5jIGFsbElzTmlsKHhzIFtdKmJ0cmVlKSBib29sIHsKCXJlcyA6PSB0cnVlCglmb3IgXywgeCA6PSByYW5nZSB4cyB7CgkJcmVzID0gKHJlcyAmJiB4ID09IG5pbCkKCX0KCXJldHVybiByZXMKfQoKZnVuYyBtYWluKCkgewoJdmFyIHQgKmJ0cmVlCgoJdCA9IGJ1aWxkVHJlZShbXWludHs1MCwgMzAsIDcwLCAyMCwgNDAsIDYwLCA4MCwgMjUsIDU1LCA2NSwgNzUsIDg1LCA5MH0pCglwdCh0KQoJZm10LlByaW50bG4oIi0tLS0g44Kt44O8MjDjgpLliYrpmaTjgZfjgabmp4vpgKDjga7lpInljJbjgpLopovjgabjgb/jgosiKQoJdCA9IHJlbW92ZSh0LCAyMCkKCXB0KHQpCn0K