import random
def AllPairsNonDecreasingPaths(E, n):
p = 1234567891 #large prime ${\color{commentcolour} p > n^3 \log n}$
r = random.randint(0,p) #random number ${\color{commentcolour} r}$ in [0,p)
powr = [1] #Precompute powers of ${\color{commentcolour} r }$
for i in range(n): #powr[i] ${\color{commentcolour} \triangleq }$ ${\color{commentcolour} r^i }$ (mod p)
powr.append((powr[-1] * r) % p)
N = 1<<(n-1).bit_length() #round n to next power of 2
tree = [ [0]*(2*N) for _ in range(n) ]
def update(v,node,val):
while node > 0:
tree[v][node] += val
node >>= 1
#Functions for finding new paths and adding them
def FindNewPaths(a,b,node):
if tree[a][node] == tree[b][node]: return []
if node >= N:
u = node - N #leaf node
if path[u][a] is None:
return [(u,a,b)]
return [(u,b,a)]
return FindNewPaths(a,b,2*node) + FindNewPaths(a,b,2*node+1)
def AddNewPath(u, v, par):
path[u][v] = par
update(v,u+N,powr[u])
#Main routine for finding all pairs non-decreasing paths
path = [ [None] * n for _ in range(n) ]
for i in range(n):
AddNewPath(i,i,i)
for (a,b) in E:
for (u,v,par) in FindNewPaths(a,b,1):
AddNewPath(u,v,par)
return path
print(AllPairsNonDecreasingPaths([(1,2),(0,1)], 3))
#Returns [[0, 0, None], [1, 1, 1], [1, 2, 2]]
def RecoverPath(path,u,v):
if path[u][v] is None: return None
if u == v: return [u]
return RecoverPath(path, u, path[u][v]) + [ v ]
path = AllPairsNonDecreasingPaths([(1,2),(0,1)], 3)
print(RecoverPath(path, 2, 0)) #Returns [2,1,0]
print(RecoverPath(path, 0, 2)) #Returns None
aW1wb3J0IHJhbmRvbQogCmRlZiBBbGxQYWlyc05vbkRlY3JlYXNpbmdQYXRocyhFLCBuKToKICAgIHAgPSAxMjM0NTY3ODkxICAgICAgICAgICAgICAgICAgICAgICAgICAgICNsYXJnZSBwcmltZSAke1xjb2xvcntjb21tZW50Y29sb3VyfSBwID4gbl4zIFxsb2cgbn0kCiAgICByID0gcmFuZG9tLnJhbmRpbnQoMCxwKSAgICAgICAgICAgICAgICAgICAjcmFuZG9tIG51bWJlciAke1xjb2xvcntjb21tZW50Y29sb3VyfSByfSQgaW4gWzAscCkKICAgIHBvd3IgPSBbMV0gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICNQcmVjb21wdXRlIHBvd2VycyBvZiAke1xjb2xvcntjb21tZW50Y29sb3VyfSByIH0kCiAgICBmb3IgaSBpbiByYW5nZShuKTogICAgICAgICAgICAgICAgICAgICAgICAjcG93cltpXSAke1xjb2xvcntjb21tZW50Y29sb3VyfSBcdHJpYW5nbGVxIH0kICR7XGNvbG9ye2NvbW1lbnRjb2xvdXJ9IHJeaSB9JCAobW9kIHApCiAgICAgICAgcG93ci5hcHBlbmQoKHBvd3JbLTFdICogcikgJSBwKQogCiAgICBOID0gMTw8KG4tMSkuYml0X2xlbmd0aCgpICAgICAgICAgICAgICAgICAjcm91bmQgbiB0byBuZXh0IHBvd2VyIG9mIDIKICAgIHRyZWUgPSBbIFswXSooMipOKSBmb3IgXyBpbiByYW5nZShuKSBdCiAgICBkZWYgdXBkYXRlKHYsbm9kZSx2YWwpOgogICAgICAgIHdoaWxlIG5vZGUgPiAwOgogICAgICAgICAgICB0cmVlW3ZdW25vZGVdICs9IHZhbAogICAgICAgICAgICBub2RlID4+PSAxCiAKICAgICNGdW5jdGlvbnMgZm9yIGZpbmRpbmcgbmV3IHBhdGhzIGFuZCBhZGRpbmcgdGhlbQogICAgZGVmIEZpbmROZXdQYXRocyhhLGIsbm9kZSk6CiAgICAgICAgaWYgdHJlZVthXVtub2RlXSA9PSB0cmVlW2JdW25vZGVdOiByZXR1cm4gW10KICAgICAgICBpZiBub2RlID49IE46ICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICB1ID0gbm9kZSAtIE4gICAgICAgICAgICAgICAgICAgICAgI2xlYWYgbm9kZQogICAgICAgICAgICBpZiBwYXRoW3VdW2FdIGlzIE5vbmU6IAogICAgICAgICAgICAgICAgcmV0dXJuIFsodSxhLGIpXQogICAgICAgICAgICByZXR1cm4gWyh1LGIsYSldCiAgICAgICAgcmV0dXJuIEZpbmROZXdQYXRocyhhLGIsMipub2RlKSArIEZpbmROZXdQYXRocyhhLGIsMipub2RlKzEpCiAgICBkZWYgQWRkTmV3UGF0aCh1LCB2LCBwYXIpOgogICAgICAgIHBhdGhbdV1bdl0gPSBwYXIKICAgICAgICB1cGRhdGUodix1K04scG93clt1XSkKIAogICAgI01haW4gcm91dGluZSBmb3IgZmluZGluZyBhbGwgcGFpcnMgbm9uLWRlY3JlYXNpbmcgcGF0aHMKICAgIHBhdGggPSBbIFtOb25lXSAqIG4gZm9yIF8gaW4gcmFuZ2UobikgXQogICAgZm9yIGkgaW4gcmFuZ2Uobik6CiAgICAgICAgQWRkTmV3UGF0aChpLGksaSkKICAgIGZvciAoYSxiKSBpbiBFOgogICAgICAgIGZvciAodSx2LHBhcikgaW4gRmluZE5ld1BhdGhzKGEsYiwxKToKICAgICAgICAgICAgQWRkTmV3UGF0aCh1LHYscGFyKQogCiAgICByZXR1cm4gcGF0aAogCnByaW50KEFsbFBhaXJzTm9uRGVjcmVhc2luZ1BhdGhzKFsoMSwyKSwoMCwxKV0sIDMpKQogICAgICAgICAgICAjUmV0dXJucyBbWzAsIDAsIE5vbmVdLCBbMSwgMSwgMV0sIFsxLCAyLCAyXV0KICAgICAgICAgICAgCmRlZiBSZWNvdmVyUGF0aChwYXRoLHUsdik6CiAgICBpZiBwYXRoW3VdW3ZdIGlzIE5vbmU6IHJldHVybiBOb25lCiAgICBpZiB1ID09IHY6IHJldHVybiBbdV0KICAgIHJldHVybiBSZWNvdmVyUGF0aChwYXRoLCB1LCBwYXRoW3VdW3ZdKSArIFsgdiBdCgpwYXRoID0gQWxsUGFpcnNOb25EZWNyZWFzaW5nUGF0aHMoWygxLDIpLCgwLDEpXSwgMykKcHJpbnQoUmVjb3ZlclBhdGgocGF0aCwgMiwgMCkpICAjUmV0dXJucyBbMiwxLDBdCnByaW50KFJlY292ZXJQYXRoKHBhdGgsIDAsIDIpKSAgI1JldHVybnMgTm9uZQ==