Submission #37129172
Source Code Expand
Copy
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
הההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההה
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
class IntegerRelationUnionFind():
def __init__(self, n):
one = 2
zero = 0
add = lambda x, y: x + y
minus = lambda x, y: x - y
mult = lambda x, y: x * y // 2 if x * y % 2 == 0 else 1 // 0
div = lambda x, a: x * 2 // a if x * 2 % a == 0 else 1 // 0
randa = lambda: randrange(-2, 3, 4)
randx = lambda: randrange(-10, 22, 2)
self.n = n
self.guf = GeneralRelationUnionFind(n, one, zero, add, minus, mult, div, randa, randx)
# self.guf.check()
def set_sum(self, i, j, s):
# vi + vj = s
ret = self.guf.unite(i, j, -2, s * 2)
if self.guf.getvalue(i) is not None and self.guf.getvalue(i) % 2:
return 0
return ret
def set_dif(self, i, j, s):
# vj = vi + s
ret = self.guf.unite(i, j, 2, s * 2)
if self.guf.getvalue(i) is not None and self.guf.getvalue(i) % 2:
return 0
return ret
def relation(self, i, j):
a, b = self.guf.relation(i, j)
return (a // 2, b // 2)
def getvalue(self, i):
ret = self.guf.getvalue(i)
if ret is None:
return None
assert ret % 2 == 0
return ret // 2
class PotentialUnionFind():
def __init__(self, n):
self.one = 1
self.zero = 0
self.add = lambda x, y: x + y
self.minus = lambda x, y: x - y
self.mult = lambda x, y: x * y
self.div = lambda x, a: x // a
self.randa = lambda: 1
self.randx = lambda: randrange(-20, 21)
self.n = n
self.guf = GeneralRelationUnionFind(n, one, zero, add, minus, mult, div, randa, randx)
# self.guf.check()
def unite(self, i, j, s):
# vj = vi + s
ret = self.guf.unite(i, j, 1, s)
return ret
def diff(self, i, j):
a, b = self.guf.relation(i, j)
return b
def getvalue(self, i):
ret = self.guf.getvalue(i)
if ret is None:
return None
return ret
def setvalue(self, i, v):
ret = self.guf.setvalue(i, v)
return ret
def same(self, i, j):
ret = self.guf.same(i, j)
return ret
class GeneralRelationUnionFind():
def __init__(self, n, one, zero, add, minus, mult, div, randa = None, randx = None):
self.one = one
self.zero = zero
self.add = add
self.minus = minus
self.mult = mult
self.div = div
self.randa = randa
self.randx = randx
self.n = n
self.PA = [-1] * n
self.rel = [(self.one, self.zero)] * n
self.value = [None] * n
self.contradiction = 0
self.contradiction_str = "!"
def check(self, m = 1000):
for _ in range(m):
x1 = self.randx()
x2 = self.randx()
x3 = self.randx()
a1 = self.randa()
# One Check
assert self.mult(a1, self.one) == self.mult(self.one, a1) == a1
# Zero Check
assert self.add(x1, self.zero) == self.add(self.zero, x1) == x1
assert self.minus(x1, self.zero) == x1
# Minus Check
assert self.add(self.minus(x1, x2), x2) == x1
# Add
assert self.add(x1, x2) == self.add(x2, x1)
assert self.add(self.add(x1, x2), x3) == self.add(x1, self.add(x2, x3))
# Mult
assert self.mult(x1, x2) == self.mult(x2, x1)
# Div
assert self.mult(self.div(x1, a1), a1) == x1
aa = self.minus(self.one, a1)
if aa != self.zero:
assert self.mult(self.div(x1, aa), aa) == x1
print("Check OK !!!")
def root(self, x):
x0 = x
sa, sb = self.one, self.zero
while self.PA[x] >= 0:
a, b = self.rel[x]
sa, sb = self.mult(sa, a), self.add(self.mult(sa, b), sb)
x = self.PA[x]
return x, sa, sb
def relation(self, x, y):
rx, ax, bx = self.root(x)
ry, ay, by = self.root(y)
if rx == ry:
return (self.div(ay, ax), self.minus(by, self.div(self.mult(ay, bx), ax)))
else:
return None
def getvalue(self, x):
rx, ax, bx = self.root(x)
if self.value[rx] is None:
return None
if self.value[rx] == self.contradiction_str:
return self.contradiction_str
return self.add(self.mult(self.value[rx], ax), bx)
def setvalue(self, x, v):
vx = self.getvalue(x)
if vx is not None:
if vx == v:
return 1
rx, ax, bx = self.root(x)
self.value[rx] = self.contradiction_str
self.contradiction = 1
return 0
rx, ax, bx = self.root(x)
self.value[rx] = self.div(self.minus(v, bx), ax)
return 1
def same(self, x, y):
# 関係式に関係なく、通常 UF で連結かどうかを判定
if self.root(x)[0] == self.root(y)[0]:
return 1
return 0
def unite(self, x, y, a, b):
# y = ax + b
# 新たに矛盾が発生すれば 0 を返す
rx, ax, bx = self.root(x)
ry, ay, by = self.root(y)
vx = self.getvalue(x)
vy = self.getvalue(y)
if vx == self.contradiction_str or vy == self.contradiction_str:
if rx != ry:
self.value[rx] = self.contradiction_str
self.value[ry] = self.contradiction_str
if self.PA[ry] >= self.PA[rx]:
self.PA[rx] += self.PA[ry]
self.PA[ry] = rx
else:
self.PA[ry] += self.PA[rx]
self.PA[rx] = ry
elif vx is None and vy is None:
if rx == ry:
aa = self.minus(self.mult(a, ax), ay)
bb = self.minus(by, self.add(b, self.mult(a, bx)))
if aa == self.zero:
if bb == self.zero:
# print("Consistent with prior information. Do nothing")
pass
else:
# print("NG")
self.contradiction = 1
self.value[rx] = self.contradiction_str
return 0
else:
r = self.div(bb, aa)
self.value[rx] = r
# print("Value Identified", r)
else:
if self.PA[ry] >= self.PA[rx]:
self.PA[rx] += self.PA[ry]
self.rel[ry] = (self.div(self.mult(ax, a), ay), self.div(self.minus(self.add(self.mult(a, bx), b), by), ay))
self.PA[ry] = rx
else:
self.PA[ry] += self.PA[rx]
aax = self.mult(a, ax)
self.rel[rx] = (self.div(ay, aax), self.div(self.minus(by, self.add(b, self.mult(a, bx))), aax))
self.PA[rx] = ry
elif vx is None:
if self.PA[ry] >= self.PA[rx]:
self.PA[rx] += self.PA[ry]
self.rel[ry] = (self.div(self.mult(ax, a), ay), self.div(self.minus(self.add(self.mult(a, bx), b), by), ay))
self.PA[ry] = rx
_vx = self.div(self.minus(vy, b), a)
_vrx = self.div(self.minus(_vx, bx), ax)
self.value[rx] = _vrx
else:
self.PA[ry] += self.PA[rx]
aax = self.mult(a, ax)
self.PA[rx] = ry
self.rel[rx] = (self.div(ay, aax), self.div(self.minus(by, self.add(b, self.mult(a, bx))), aax))
elif vy is None:
if self.PA[ry] >= self.PA[rx]:
self.PA[rx] += self.PA[ry]
self.PA[ry] = rx
self.rel[ry] = (self.div(self.mult(ax, a), ay), self.div(self.minus(self.add(self.mult(a, bx), b), by), ay))
else:
self.PA[ry] += self.PA[rx]
aax = self.mult(a, ax)
self.rel[rx] = (self.div(ay, aax), self.div(self.minus(by, self.add(b, self.mult(a, bx))), aax))
self.PA[rx] = ry
_vy = self.add(self.mult(vx, a), b)
_vry = self.div(self.minus(_vy, by), ay)
self.value[ry] = _vry
else:
if self.add(self.mult(vx, a), b) == vy:
if rx == ry:
# print("Consistent with prior information. Do nothing")
pass
else:
# print("Consistent with prior information, but need to connect")
if self.PA[ry] >= self.PA[rx]:
self.PA[rx] += self.PA[ry]
self.rel[ry] = (self.div(self.mult(ax, a), ay), self.div(self.minus(self.add(self.mult(a, bx), b), by), ay))
self.PA[ry] = rx
else:
self.PA[ry] += self.PA[rx]
aax = self.mult(a, ax)
self.rel[rx] = (self.div(ay, aax), self.div(self.minus(by, self.add(b, self.mult(a, bx))), aax))
self.PA[rx] = ry
else:
if self.PA[ry] >= self.PA[rx]:
self.PA[rx] += self.PA[ry]
self.PA[ry] = rx
self.value[rx] = self.contradiction_str
else:
self.PA[ry] += self.PA[rx]
self.PA[rx] = ry
self.value[ry] = self.contradiction_str
self.contradiction = 1
return 0
return 1
def size(self, x):
return -self.PA[self.root(x)]
def groups(self):
G = [[] for _ in range(self.n)]
for i in range(self.n):
G[self.root(i)].append(i)
return [g for g in G if g]
def groups_index(self):
G = [[] for _ in range(self.n)]
for i in range(self.n):
G[self.root(i)[0]].append(i)
cnt = 0
GG = []
I = [-1] * self.n
for i in range(self.n):
if G[i]:
GG.append(G[i])
I[i] = cnt
cnt += 1
return GG, I
def group_size(self):
G = [[] for _ in range(self.n)]
for i in range(self.n):
G[self.root(i)].append(i)
return [len(g) for g in G if g]
def debug(self):
GG, I = self.groups_index()
print("GG =", GG)
print("I =", I)
print("PA =", self.PA)
print("rel =", self.rel)
P = 31
from random import randrange, random
if 0:
# 係数はZで、積閉集合は {1, -1}
# 2 で割る必要があるため、2倍した値を持っている
one = 2
zero = 0
add = lambda x, y: x + y
minus = lambda x, y: x - y
mult = lambda x, y: x * y // 2 if x * y % 2 == 0 else 1 // 0
div = lambda x, a: x * 2 // a if x * 2 % a == 0 else 1 // 0
randa = lambda: randrange(-2, 3, 4)
randx = lambda: randrange(-20, 22, 2)
elif 1:
# 係数はZで、積閉集合は {1}
# 通常の Potential UF
one = 1
zero = 0
add = lambda x, y: x + y
minus = lambda x, y: x - y
mult = lambda x, y: x * y
div = lambda x, a: x // a
randa = lambda: 1
randx = lambda: randrange(-20, 21)
elif 0:
# 係数が non-zero float
one = 1.0
zero = 0.0
add = lambda x, y: x + y
minus = lambda x, y: x - y
mult = lambda x, y: x * y
div = lambda x, a: x / a
randa = lambda: random() * 2 - 1
randx = lambda: random() * 20 - 10
elif 0:
# 係数が Z/pZ
one = 1
zero = 0
add = lambda x, y: (x + y) % P
minus = lambda x, y: (x - y) % P
mult = lambda x, y: x * y % P
div = lambda x, a: x * pow(a, P - 2, P) % P
randa = lambda: randrange(1, P)
randx = lambda: randrange(P)
elif 0:
# 係数が Z/2Z で差のみ与えられる(通常の Potential UF)
one = 1
zero = 0
add = lambda x, y: x ^ y
minus = lambda x, y: x ^ y
mult = lambda x, y: x & y
div = lambda x, a: x & a
randa = lambda: 1
randx = lambda: randrange(2)
DEBUG = 0
if DEBUG:
n = 5
uf = GeneralRelationUnionFind(n, one, zero, add, minus, mult, div, randa, randx)
uf.check()
if 0:
uf.unite(1, 2, 1, 3)
uf.unite(2, 4, 1, 10)
# assert uf.unite(1, 2, 2, 3)
assert uf.unite(3, 4, 2, 10)
assert uf.unite(2, 3, -2, 2)
assert uf.unite(2, 3, 2, 4)
# assert uf.unite(2, 4, 1, 1)
assert uf.setvalue(4, 16)
for i in range(5):
print("Value ", i, "=", uf.getvalue(i))
print(uf.relation(4, 1))
uf.debug()
print("-" * 20)
uf = IntegerRelationUnionFind(11)
assert uf.set_sum(1, 2, 3)
assert uf.set_dif(1, 2, 7)
assert uf.set_sum(4, 1, 11)
assert uf.set_sum(6, 9, 3)
assert uf.set_sum(6, 10, 12)
print(uf.relation(9, 10))
for i in range(10):
print(i, uf.getvalue(i))
print("-" * 20)
##### ここから #####
if 0:
# ABC 280-F
N, M, Q = map(int, input().split())
uf = PotentialUnionFind(N)
for _ in range(M):
a, b, c = map(int, input().split())
a, b = a-1, b-1
ret = uf.unite(a, b, c)
for _ in range(Q):
x, y = [int(a) - 1 for a in input().split()]
if uf.same(x, y):
if uf.guf.value[uf.guf.root(x)[0]] == "!":
print("inf")
else:
print(uf.diff(x, y))
else:
print("nan")
# ABC 087-D
N, M = map(int, input().split())
uf = PotentialUnionFind(N)
for _ in range(M):
l, r, d = map(int, input().split())
l, r = l-1, r-1
ret = uf.unite(l, r, d)
if not ret:
print("No")
break
else:
print("Yes")
Submission Info
Submission Time |
|
Task |
D - People on a Line |
User |
Kiri8128 |
Language |
PyPy3 (7.3.0) |
Score |
400 |
Code Size |
14338 Byte |
Status |
AC |
Exec Time |
744 ms |
Memory |
91296 KB |
Judge Result
Set Name |
Sample |
All |
Score / Max Score |
0 / 0 |
400 / 400 |
Status |
|
|
Set Name |
Test Cases |
Sample |
sample01.txt, sample02.txt, sample03.txt, sample04.txt, sample05.txt |
All |
01.txt, 02.txt, 03.txt, 04.txt, 05.txt, 06.txt, 07.txt, 08.txt, 09.txt, 10.txt, 11.txt, 12.txt, 13.txt, 14.txt, 15.txt, 16.txt, 17.txt, 18.txt, 19.txt, 20.txt, 21.txt, 22.txt, 23.txt, 24.txt, 25.txt, 26.txt, 27.txt, 28.txt, 29.txt, 30.txt, 31.txt, 32.txt, 33.txt, 34.txt, 35.txt, 36.txt, 37.txt, 38.txt, 39.txt, 40.txt, 41.txt, 42.txt, sample01.txt, sample02.txt, sample03.txt, sample04.txt, sample05.txt |
Case Name |
Status |
Exec Time |
Memory |
01.txt |
AC |
744 ms |
82056 KB |
02.txt |
AC |
623 ms |
87396 KB |
03.txt |
AC |
326 ms |
87092 KB |
04.txt |
AC |
700 ms |
89580 KB |
05.txt |
AC |
340 ms |
86120 KB |
06.txt |
AC |
559 ms |
91296 KB |
07.txt |
AC |
344 ms |
84860 KB |
08.txt |
AC |
535 ms |
89948 KB |
09.txt |
AC |
498 ms |
87664 KB |
10.txt |
AC |
498 ms |
87856 KB |
11.txt |
AC |
430 ms |
87968 KB |
12.txt |
AC |
350 ms |
85228 KB |
13.txt |
AC |
599 ms |
88320 KB |
14.txt |
AC |
513 ms |
87240 KB |
15.txt |
AC |
373 ms |
88000 KB |
16.txt |
AC |
504 ms |
89028 KB |
17.txt |
AC |
648 ms |
89060 KB |
18.txt |
AC |
612 ms |
87244 KB |
19.txt |
AC |
531 ms |
88060 KB |
20.txt |
AC |
547 ms |
89136 KB |
21.txt |
AC |
389 ms |
86908 KB |
22.txt |
AC |
432 ms |
86804 KB |
23.txt |
AC |
372 ms |
88460 KB |
24.txt |
AC |
410 ms |
88140 KB |
25.txt |
AC |
629 ms |
88596 KB |
26.txt |
AC |
652 ms |
87544 KB |
27.txt |
AC |
453 ms |
88152 KB |
28.txt |
AC |
526 ms |
87172 KB |
29.txt |
AC |
445 ms |
87848 KB |
30.txt |
AC |
525 ms |
88612 KB |
31.txt |
AC |
448 ms |
89116 KB |
32.txt |
AC |
530 ms |
88048 KB |
33.txt |
AC |
486 ms |
86060 KB |
34.txt |
AC |
375 ms |
86748 KB |
35.txt |
AC |
450 ms |
87032 KB |
36.txt |
AC |
444 ms |
89256 KB |
37.txt |
AC |
441 ms |
88772 KB |
38.txt |
AC |
446 ms |
87456 KB |
39.txt |
AC |
457 ms |
86872 KB |
40.txt |
AC |
462 ms |
87940 KB |
41.txt |
AC |
125 ms |
79928 KB |
42.txt |
AC |
363 ms |
88556 KB |
sample01.txt |
AC |
117 ms |
77440 KB |
sample02.txt |
AC |
118 ms |
77564 KB |
sample03.txt |
AC |
117 ms |
77664 KB |
sample04.txt |
AC |
121 ms |
77508 KB |
sample05.txt |
AC |
121 ms |
77656 KB |