새소식

PS/백준

[백준/2820] 자동차 공장 (Python)

  • -

Problem : https://www.acmicpc.net/problem/2820

 

2820번: 자동차 공장

상근이는 자동차를 매우 좋아한다. 자동차 공장에 취직한 상근이는 계속된 승진 끝에 드디어 사장이 되었다. 공장에는 총 N명의 직원이 있다. 상근이를 제외한 모든 직원은 한 명의 상사가 있다.

www.acmicpc.net

 

Difficulty : Platinum 3

 

Status : Solved

 

Time : 01:08:55

 


 

문제 설명

 

더보기

 

상근이는 자동차를 매우 좋아한다. 자동차 공장에 취직한 상근이는 계속된 승진 끝에 드디어 사장이 되었다. 공장에는 총 N명의 직원이 있다. 상근이를 제외한 모든 직원은 한 명의 상사가 있다. (상근이는 모든 사람의 상사이다) 상근이의 번호는 1번이고, 나머지 직원의 번호는 2부터 N이다.

모든 직원은 자신의 모든 부하 직원(직속 부하와 부하의 부하등등을 모두 포함)의 월급을 인상하거나 삭감할 수 있다. 상근이는 권력 남용을 막기 위해 직원의 월급을 모니터링 하려고 한다.

월급의 변화를 모니터링하는 프로그램을 작성하시오.

모든 직원의 월급은 항상 양의 정수이고 2^31-1 이하이다.

 

 

입력 및 출력

 

더보기

입력

 

첫째 줄에 직원의 수 N과 월급 변화와 조사 쿼리의 수 M이 주어진다. (1 ≤ N, M ≤ 500,000)

다음 N개 줄의 i번째 줄에는 직원 i의 초기 월급과 상사의 번호가 주어진다. (상근이는 상사가 없기 때문에, 초기 월급만 주어진다)

다음 M개 줄에는 월급 변화와 조사 쿼리가 주어진다.

1. p a x가 주어진 경우 a의 모든 부하의 월급을 x만큼 증가시킨다. (-10,000 ≤ x ≤ 10,000)
2. u a가 주어진 경우에는 a의 월급을 출력한다.

 

출력

 

입력으로 u가 주어질 때마다 해당하는 직원의 월급을 출력한다.

 

입력 예시

 

2 3
5
3 1
p 1 5
u 2
u 1

 

출력 예시

 

8
5

 

 


 

풀이

 

 

이 문제를 참고하자.

 

2023.12.28 - [PS/백준] - [백준/16404] 주식회사 승범이네 (Python)

 

[백준/16404] 주식회사 승범이네 (Python)

Problem : https://www.acmicpc.net/problem/16404 16404번: 주식회사 승범이네 첫 번째 줄에 승범이를 포함한 판매원들의 수 N(1 ≤ N ≤ 100,000), 명령의 수 M(1 ≤ M ≤ 100,000)이 주어진다. 판매원들은 1번부터 N번

magentino.tistory.com

 

핵심은 동일하다. 그대로 트리 형태로 진행하게 되면, 극단적으로 편향된 경우 O(NM)의 시간복잡도가 소요된다. 따라서 오일러 경로 테크닉을 이용해 세그먼트 트리 형태로 전환하고, 구간 업데이트 및 서칭을 로그 시간복잡도에 끝낼 수 있는 lazy propagation 을 사용해서 해결한다.

 

단, 파이썬은 매우 느린 언어다. 즉 오일러 경로 테크닉, 트리의 업데이트, 서칭 모두 비재귀 방식으로 구현되어야 함에 주의하자.   

 

풀이 코드

import sys
input = sys.stdin.readline

N, M = map(int, input().split())
children = [list() for _ in range(N+1)]
parents = [[0, 0] for _ in range(N+1)]
index = [[0, 0] for _ in range(N+1)]
salary = [0]*(N+1)

def dfs():
  q = [(1, 0)]
  leaf_q = []
  cnt = 0
  while q:
    n, p = q.pop()
    cnt += 1
    index[n][0] = cnt
    if not children[n]:
      leaf_q.append(n)
      index[n][1] = cnt
      continue
    for c in children[n]:
      q.append((c, n))
  while leaf_q:
    n = leaf_q.pop()
    p = parents[n][0]
    if p :
      if index[p][1] < index[n][1] :
        index[p][1] = index[n][1]
      parents[p][1] -= 1
      if not parents[p][1] :
        leaf_q.append(p)

def propagate(start, end, idx):
  if start != end:
    lazy[idx*2 + 1] += lazy[idx]
    lazy[idx*2] += lazy[idx]
  else:
    tree[idx] += lazy[idx]
  lazy[idx] = 0

def update(left, right, val):
  q = [(0, N, 1)]
  while q :
    s, e, i = q.pop()
    propagate(s, e, i)
    if left > e or right < s :
      continue
    if left <= s <= e <= right :
      lazy[i] += val
      propagate(s, e, i)
      continue
    mid = (s + e) // 2
    q.append((s, mid, i*2))
    q.append((mid+1, e, i*2+1))

def search(target):
  start, end, idx = 0, N, 1
  while start < end:
    propagate(start, end, idx)
    mid = (start + end) // 2
    if target <= mid:
      end = mid
      idx = idx*2
    else :
      start = mid+1
      idx = idx*2+1
  propagate(start, end, idx)
  return tree[idx]

salary[1] = int(input())
for i in range(2, N + 1):
  s, p = map(int, input().split())
  salary[i] = s
  parents[i][0] = p
  parents[p][1] += 1
  children[p].append(i)

dfs()
tree = [0]*(4*N + 4)
lazy = [0]*(4*N + 4)

for _ in range(M):
  q, *cmd = input().split()
  if q == 'p':
    a, b = map(int, cmd)
    left, right = index[a]
    if left == right :
      continue
    update(left + 1, right, b)
  else:
    a = int(cmd[0])
    result = search(index[a][0])
    print(result + salary[a])

풀이 완료!

Contents

포스팅 주소를 복사했습니다

이 글이 도움이 되었다면 공감 부탁드립니다.