mirror of
https://github.com/heqin-zhu/algorithm.git
synced 2024-03-22 13:30:46 +08:00
117 lines
3.5 KiB
Python
117 lines
3.5 KiB
Python
''' mbinary
|
|
#########################################################################
|
|
# File : loserTree.py
|
|
# Author: mbinary
|
|
# Mail: zhuheqin1@gmail.com
|
|
# Blog: https://mbinary.xyz
|
|
# Github: https://github.com/mbinary
|
|
# Created Time: 2018-05-19 23:06
|
|
# Description:
|
|
#########################################################################
|
|
'''
|
|
|
|
from winnerTree import winnerTree
|
|
class loserTree:
|
|
'''if i<=lowExt p = (i+offset)//2
|
|
else p = (i+n-1-lowExt)//2
|
|
s is the num of the full subtree node
|
|
p is the index of tree
|
|
i is the index of players
|
|
offset is a num 2^k-1 just bigger than n
|
|
lowExt is the double node num of the lowest layer of the tree
|
|
'''
|
|
def __init__(self,players,reverse=False):
|
|
self.n=len(players)
|
|
self.tree = [0]*self.n
|
|
players.insert(0,0)
|
|
self.players=players
|
|
self.reverse=reverse
|
|
self.getNum()
|
|
self.tree[0] = self.initTree(1)
|
|
self.dir=None
|
|
def getNum(self):
|
|
i=1
|
|
while 2*i< self.n:i=i*2
|
|
if 2*i ==self. n:
|
|
self.lowExt=0
|
|
self.s = 2*i-1
|
|
else:
|
|
self.lowExt = (self.n-i)*2
|
|
self.s = i-1
|
|
self.offset = 2*i-1
|
|
def treeToArray(self,p):
|
|
return 2*p-self.offset if p>self.s else 2*p+self.lowExt-self.n+1
|
|
def arrayToTree(self,i):
|
|
return (i+self.offset)//2 if i<=self.lowExt else (i-self.lowExt+ self.n-1)//2
|
|
def win(self,a,b):
|
|
return a<b if self.reverse else a>b
|
|
def initTree(self,p):
|
|
if p>=self.n:
|
|
delta = p%2 #!!! good job notice delta mark the lchild or rchlid
|
|
return self.players[self.treeToArray(p//2)+delta]
|
|
l = self.initTree(2*p)
|
|
r = self.initTree(2*p+1)
|
|
if self.win(r,l):
|
|
self.tree[p] = l
|
|
self.dir = 'r'
|
|
return r
|
|
else :
|
|
self.tree[p] = r
|
|
self.dir = 'l'
|
|
return l
|
|
def getWinIdx(self,idx=1):
|
|
while 2*idx<self.n:
|
|
idx = 2*idx if self.tree[idx].dir == 'l' else idx*2+1
|
|
return self.treeToArray(idx)
|
|
def winner(self):
|
|
i = self.getWinIdx()
|
|
i = i+1 if self.players[i] !=self.tree[0] else i
|
|
return self.tree[0],i
|
|
def getOppo(self,i,x,p):
|
|
oppo=None
|
|
if 2*p<self.n:oppo=self.tree[2*p]
|
|
elif i<=self.lowExt:oppo=self.players[i-1+i%2*2]
|
|
else:
|
|
lpl= self.players[2*p+self.lowExt-self.n+1]
|
|
oppo = lpl if lpl!=x else self.players[2*p+self.lowExt-self.n+2]
|
|
return oppo
|
|
def update(self,i,x):
|
|
''' i is 1-indexed which is the num of player
|
|
and x is the new val of the player '''
|
|
self.players[i]=x
|
|
p = self.arrayToTree(i)
|
|
oppo =self.getOppo(i,x,p)
|
|
self.tree[p],winner = x , oppo if self.win(oppo,x) else oppo,x
|
|
p=p//2
|
|
while p:
|
|
l = self.tree[p*2]
|
|
r = None
|
|
if 2*p+1<self.n:r=self.tree[p*2+1] #notice this !!!
|
|
else:r = self.players[2*p+self.lowExt-self.n+1]
|
|
self.tree[p] = l if self.win(l,r) else r
|
|
p=p//2
|
|
# to do update-func the change of every node's dir and loser
|
|
|
|
if __name__ =='__main__':
|
|
s= [4,1,6,7,9,5234,0,2,7,4,123]
|
|
t = winnerTree(s)
|
|
for i in s:
|
|
val,idx=t.winner()
|
|
print(val,idx)
|
|
t.update(idx,-1)
|
|
|
|
|
|
'''
|
|
[0, 4, 1, 6, 7, 9, 5234, 0, 2, 123] [0, 5234, 9, 5234, 6, 9, 5234, 123, 4]
|
|
5234 6
|
|
123 9
|
|
9 5
|
|
7 4
|
|
6 3
|
|
4 1
|
|
2 8
|
|
1 2
|
|
0 7
|
|
-1 1
|
|
'''
|