https://www.acmicpc.net/problem/14268
https://www.acmicpc.net/problem/14267
원래 버전은 내리갈굼이었는데 순화됐다.
(내리칭찬3)
<문제설명>
최대 1e5개의 정점을 갖는 트리가 주어진다. 각 정점마다 칭찬수치를 갖는다. 다음 두가지 쿼리에 대해 처리하라
1. x, w : x정점의 칭찬수치를 w만큼 더한다.
2. x : x정점의 후손들의 칭찬수치를 모두 더하여 출력
<풀이>
트리를 dfs하여 정점(x)마다 방문순서(l[x])를 기록해둔다면, 정점x를 루트로하는 서브트리는 [l[x], l[x]+#children[x]]의 구간을 갖는다.
l[x],r[x]사이의 칭찬수치값을 모두 더해준다.
<코드>
const int MAX = 1e5 + 4;
const int SMAX = (1 << 18);
int n, qq, l[MAX], r[MAX], seg[SMAX];
vector<int> g[MAX];
int counter;
void dfs(int u) {
l[u] = counter++;
for (int v : g[u]) dfs(v);
r[u] = counter - 1;
}
void update(int i, int x) {
i += SMAX / 2;
seg[i] += x;
while (i > 1) {
i /= 2;
seg[i] = seg[i * 2] + seg[i * 2 + 1];
}
}
int val(int s, int e, int i, int ns, int ne) {
if (e < ns || ne < s) return 0;
if (s <= ns && ne <= e) return seg[i];
int md = (ns + ne) / 2;
return val(s, e, i * 2, ns, md) + val(s, e, i * 2 + 1, md + 1, ne);
}
int val(int s, int e) {
return val(s, e, 1, 0, SMAX / 2 - 1);
}
int main() {
FAST; cin >> n >> qq;
for (int i = 1, x; i <= n; i++) {
cin >> x; if (i == 1) continue;
g[x].push_back(i);
}
dfs(1);
for (int i = 0,opt, x,w; i < qq; i++) {
cin >> opt >> x;
if (opt == 1) {
cin >> w;
update(l[x], w);
}
else cout << val(l[x], r[x]) << '\n';
}
}
(내리칭찬2)
<문제설명>
최대 1e5개의 정점을 갖는 트리가 주어진다. 각 정점마다 칭찬수치를 갖는다. 다음 두가지 쿼리에 대해 처리하라
1. x, w : x를 루트로하는 서브트리 전체에 칭찬수치를 w만큼 더한다
2. x : 정점 x의 칭찬수치를 출력
<풀이>
트리를 dfs하여 정점(x)마다 방문순서(l[x])를 기록해둔다면, 정점x를 루트로하는 서브트리는 [l[x], l[x]+#children[x]]의 구간을 갖는다.
이를 이용하여 구간 update를 해주면 된다.
주의 : 2번쿼리가 포인트 쿼리라고 seg[x+SMAX/2]를 그대로 출력하면 틀린다. lazy값을 적용하기 전의 상태일 수 있으므로 각 단계마다 propagate를 해줘야 한다. 따라서 포인트쿼리도 재귀함수를 사용하여 구해줘야 한다.
<코드>
const int MAX = 1e5 + 4;
const int SMAX = (1 << 18);
int n, qq, l[MAX], r[MAX], seg[SMAX], lazy[SMAX];
vector<int> g[MAX];
int counter;
void dfs(int u){
int cnt = 0;
l[u] = counter++;
for (int v : g[u]) dfs(v);
r[u] = counter-1;
}
void propagate(int node, int ns, int ne) {
if (lazy[node] == 0) return;
if (node < SMAX / 2) {
lazy[node * 2] += lazy[node];
lazy[node * 2+1] += lazy[node];
}
seg[node] += (ne - ns + 1) * lazy[node];
lazy[node] = 0;
}
void update(int s, int e, int k, int node, int ns, int ne) {
propagate(node, ns, ne);
if (e < ns || ne < s) return;
if (s <= ns && ne <= e) {
lazy[node] += k;
propagate(node, ns, ne);
return;
}
int md = (ns + ne) / 2;
update(s, e, k, node * 2, ns, md);
update(s, e, k, node * 2 + 1, md + 1, ne);
seg[node] += seg[node * 2] + seg[node * 2 + 1];
}
void update(int s, int e, int k) {
return update(s, e, k, 1, 0, SMAX / 2 - 1);
}
int val(int s, int e, int node, int ns, int ne) {
propagate(node, ns, ne);
if (e < ns || ne < s) return 0;
if (s <= ns && ne <= e) return seg[node];
int md = (ns + ne) / 2;
return val(s, e, node * 2, ns, md) + val(s, e, node * 2 + 1, md + 1, ne);
}
int val(int x) {
return val(x, x, 1, 0, SMAX / 2 - 1);
}
int main() {
FAST; cin >> n >> qq;
for (int i = 1, x; i <= n; i++) {
cin >> x; if (i == 1) continue;
g[x].push_back(i);
}
dfs(1);
for (int i = 0,opt,x,w; i < qq; i++) {
cin >> opt >> x;
if (opt == 1) {
cin >> w;
update(l[x], r[x], w);
}
else cout << val(l[x]) << '\n';
}
}
<생각>
펜윅트리로 짜면 lazy배열 사용하지 않고 구현할 수 있다.
'알고리즘 > 백준 & swacademy' 카테고리의 다른 글
BOJ 13309 - 트리 (레이지, ett, 트리) (3) | 2020.05.22 |
---|---|
BOJ 18437 - 회사문화 5 (레이지, ett, 트리) (0) | 2020.05.21 |
BOJ 2532 - 먹이사슬 (LIS) (0) | 2020.05.20 |
BOJ 14939 - 전구 끄기 (비트마스크, 그리디, 완탐) (0) | 2020.05.19 |
BOJ 2261 - 가장 가까운 두 점 (라인스위핑) (0) | 2020.05.19 |