BOJ

[BOJ 14287 | C++] 회사 문화 3 :: ETT(오일러 경로 테크닉)

yeonee911 2025. 3. 28. 14:13

 

코드

dfs를 이용하여 in 배열과 out 배열을 관리하고 세그먼트 트리를 활용하여 서브트리의 합을 구했습니다.

 

dfs를 비재귀로 짜는 게 습관이라서 재귀 구현은 쉽지 않았지만 N과 M시리즈를 뽀개며 공부했더니 잘 구현할 수 있었습니다. 세그먼트 트리를 오랜만에 구현했더니 처음에 몇 군데 실수가 있었습니다...😭

#include <iostream>
#include <vector>
#include <algorithm>

using namespace std;

int main() {
	ios::sync_with_stdio(false);
	cin.tie(NULL);
	cout.tie(NULL);
	
	int n, m;	cin >> n >> m;

	vector<int>in(n + 1);
	vector<int>out(n + 1);
	vector<vector<int>>g(n + 1);

	for (int i = 1;i<=n;i++) {
		int x;	cin >> x;
		if (x == -1) continue;
		g[x].push_back(i);
	}

	int cnt = 0;
	auto recursive = [&](const auto& self, int n) -> void {
		in[n] = ++cnt;
		for (auto x : g[n]) {
			self(self, x);
		}
		out[n] = cnt;
	};
	recursive(recursive, 1);
	

	int sz = 1;
	while(sz < n) sz *= 2;
	vector<int>tree(sz * 2, 0);

	auto update = [&](int i, int w) {
		i = i - 1 + sz;
		tree[i] += w;
		while(i > 1) {
			i /= 2;
			tree[i] = tree[i * 2] + tree[i * 2 + 1];
		}
	};

	auto query = [&](int l, int r) {
		l = l - 1 + sz;
		r = r - 1 + sz;
		
		int res = 0;
		while(l <= r) {
			if (l % 2 == 1)	res += tree[l], l++;
			if (r % 2 == 0) res += tree[r], r--;

			l /= 2;
			r /= 2;
		}

		return res;
	};

	for (int i = 0;i<m;i++) {
		int q, x, w;
		cin >> q >> x;
		if (q == 1) {
			cin >> w;
			update(in[x], w);
		}
		else {
			cout << query(in[x], out[x]) << '\n';
		}
	}
}