난 원래 이런 자료구조에 좀 약했는데 특히 트리 문제에서 약점을 보이고 있었다. 고로 이제 슬 취준을 해야할 시기가 왔기 때문에 더는 미루지 말고 트리 문제에 대해서 완전 정복을 해보기로 하였다
여기서 중요한것은 부모-자식 관계를 모두 포함하고 있다는 것이다




# 특정 원소가 속한 집합을 찾기
def find(parent, x):
if parent[x] == x:
return x
parent[x] = find(parent, parent[x])
return parent[x]
# 두 원소가 속한 집합을 합치기 (간선 연결한다고 생각!)
def union(parent, a, b):
rootA = find(parent, a)
rootB = find(parent, b)
if rootA < rootB:
parent[rootB] = rootA
else:
parent[rootA] = rootB
for edge in edges:
cost, a, b = edge
# 사이클이 발생하지 않는 경우에만 집합에 포함(=연결한다.)
if find(parent, a) != find(parent, b):
union(parent, a, b)
result += cost
```def mst():def lca(a,b):
## 무조건 a가 더 높은 정점이다
if level[a] < level[b]:
swap(a,b)
## 정점이 같아질때까지 거슬러 올라간다
while level[a] != level[b]:
a = parent[a]
## 정점이 같을때까지 거슬러 올라간다
while a != b:
a = parent[a]
b = parent[b]
return a
활용: 트리의 특정 순서로 노드를 처리하는 문제 (예: 이진 검색 트리 재구성).
class Node:
def __init__(self, data, left_node, right_node):
self.data = data
self.left_node = left_node
self.right_node = right_node
# 전위 순회(Preorder Traversal)
def pre_order(node):
print(node.data, end=' ')
if node.left_node != None:
pre_order(tree[node.left_node])
if node.right_node != None:
pre_order(tree[node.right_node])
# 중위 순회(Inorder Tarversal)
def in_order(node):
if node.left_node != None:
in_order(tree[node.left_node])
print(node.data, end=' ')
if node.right_node != NOne:
in_order(tree[node.right_node])
# 후위 순회(Postorder Traversal)
def post_order(node):
if node.left_node != None:
post_order(tree[node.left_node])
if node.right_node != None:
post_order(tree[node.right_node])
print(node.data, end=' ')
유형 활용 예제
1. 계층 구조 트리: 조직도, 디렉터리 구조, 부모-자식 관계
2. 이진 탐색 트리: 빠른 값 검색, 범위 쿼리 문제
3. 완전 이진 트리: 힙 구현, 정렬 문제
4. 최소 스패닝 트리: 네트워크 최소 비용 연결 문제
5. 트리의 지름: 네트워크 최장 거리 문제
6. 최소 공통 조상: 공통 관리자 찾기, 경로 계산 문제
7. 세그먼트/펜윅 트리: 구간 합/최솟값/최댓값 문제
8. 트리 순회: 트리 변환, 특정 노드 처리 순서 문제
트리에서 리프 노드란, 자식의 개수가 0인 노드를 말한다.
트리가 주어졌을 때, 노드 하나를 지울 것이다. 그 때, 남은 트리에서 리프 노드의 개수를 구하는 프로그램을 작성하시오. 노드를 지우면 그 노드와 노드의 모든 자손이 트리에서 제거된다.
예를 들어, 다음과 같은 트리가 있다고 하자.

현재 리프 노드의 개수는 3개이다. (초록색 색칠된 노드) 이때, 1번을 지우면, 다음과 같이 변한다. 검정색으로 색칠된 노드가 트리에서 제거된 노드이다.

이제 리프 노드의 개수는 1개이다.
첫째 줄에 트리의 노드의 개수 N이 주어진다. N은 50보다 작거나 같은 자연수이다. 둘째 줄에는 0번 노드부터 N-1번 노드까지, 각 노드의 부모가 주어진다. 만약 부모가 없다면 (루트) -1이 주어진다. 셋째 줄에는 지울 노드의 번호가 주어진다.
첫째 줄에 입력으로 주어진 트리에서 입력으로 주어진 노드를 지웠을 때, 리프 노드의 개수를 출력한다.
당연히 그 부모 트리밑으로만 없애면 된다고 해서 그 밑부터는 DFS로 삭제해서 해결하면 된다고 생각을 하였다. 하지만 그 노드도 삭제되어 그 위의 부모 노드도 신경을 써야하였고 또한 카운트를 하는것은 Leaf노드고 입력으로 들어오는 것은 부모노드이기때문에 부모노드가 아니면서 -2도 아닌것을 찾으면 된다!
import sys
input = sys.stdin.readline
def dfs(num, arr):
arr[num] = -2
for i in range(len(arr)):
if num == arr[i]:
dfs(i, arr)
n = int(input())
arr = list(map(int, input().split()))
k = int(input())
count = 0
dfs(k, arr)
count = 0
for i in range(len(arr)):
if arr[i] != -2 and i not in arr:
count += 1
print(count)