aacord’s memo

abcを中心にpythonで解いた問題のメモ、整理をしています。緑になった。

abc 187 E - Through Path

"「ある頂点の子孫でない頂点に xを足す」は、
「根の子孫に xを足す」と「ある頂点の子孫に -xを足す」に分けることができるので、
全てのクエリを「ある頂点の子孫に x を足す」の形に帰着することができます。"

かしこい。は?となりながら解説の言うとおりにやってみたら確かにできた。
2つ条件があって、一つが簡単に書けるときは、もう一方をその条件に帰着できないか考えるのが大事なのかなと思った。あと木の上で総和を求めていくのも初だった。

import sys
input = sys.stdin.readline
from collections import deque

n = int(input())
h = [0]*n

g = [[] * n for i in range(n)]
for i in range(n-1):
    u, v = map(int, input().split())
    u -= 1
    v -= 1
    g[u].append(v)
    g[v].append(u)
    h[i] = (u,v)
    
que = deque()
que.append((0,1))
dep = [0]*n
chk = [False]*n
chk[0] = True
cnt = 1
while que:
  now,p = que.popleft()
  if cnt == n:
    break
  for i in g[now]:
    if not chk[i]:
      dep[i] = p
      chk[i] = True
      cnt += 1
      que.append((i,p+1))
                  
ans = [0]*n
q = int(input())
for i in range(q):
  t,e,x = map(int, input().split())
  e -= 1
  a,b = h[e]
  if t == 2:
    a,b = b,a
  if dep[a] < dep[b]:
    ans[b] -= x
    ans[0] += x
  else:
    ans[a] += x
    
que = deque()
que.append(0)
chk = [False]*n
chk[0] = True
cnt = 1
while que:
  now = que.popleft()
  if cnt == n:
    break
  for i in g[now]:
    if not chk[i]:
      ans[i] += ans[now]
      chk[i] = True
      cnt += 1
      que.append(i)
    
print(*ans,sep='\n')