Algorithm (알고리즘)
Algorithm in A..Z - Fenwick Tree(Binary Indexed Tree)
강태종
2021. 3. 2. 18:05
개념
각 인덱스는 최하위 비트의 값만큼 구간을 저장하고 이를 이용하여 구간의 합을 빠르게 찾을 수 있다.
=> 1, 3, 5, 7은 최하위 비트의 값이 1 -> 구간의 길이가 1만큼의 합을 저장
=> 2, 6은 최하위 비트의 값이 2 -> 구간의 길이가 2만큼의 합을 저장
=> 4는 최하위 비트의 값이 4 -> 구간의 길이가 4만큼의 합을 저장
=> 8은 최하위 비트의 값이 8 -> 구간의 길이가 8만큼 합을 저장
작동원리
최하위 비트를 구하는 법
index & -index
Query
1-3 구간의 합을 구하면 트리에서 2, 3을 더한다.
- 3(0011)에 저장된 값을 더하고 최하위 비트(0001)를 뺀다. => 2(0010)
- 2(0010)에 저장된 값을 더하고 최하위 비트(0010)를 뺀다. => 0(0000)
- 0이면 종료한다.
1-7 구간의 합을 구하면 트리에서 4, 6, 7을 더한다.
- 7(0111)에 저장된 값을 더하고 최하위 비트(0001)를 뺀다. => 6(0110)
- 6(0110)에 저장된 값을 더하고 최하위 비트(0010)를 뺀다. => 4(0100)
- 4(0100)에 저장된 값을 더하고 최하위 비트(0100)를 뺀다. => 0(0000)
- 0이면 종료한다.
4-7 구간의 합을 구하려면 1-7까지 구간의 합과 1-3까지 구간의 합을 빼서 구한다.
Update
1의 인덱스 값을 변경하면 1, 2, 4, 8의 값을 Update한다.
- 1(0001)의 인덱스 값을 Update하고 최하위 비트(0001)를 더한다. => 2(0010)
- 2(0010)의 인덱스 값을 Update하고 최하위 비트(0010)를 더한다. => 4(0100)
- 4(0100)의 인덱스 값을 Update하고 최하위 비트(0100)를 더한다. => 8(1000)
- 8(1000)의 인덱스 값을 Update하고 최하위 비트(1000)를 더한다. => 16
- 16은 Tree의 Index를 벗어아니까 종료한다.
3의 인덱스 값을 변경하면 3, 4, 8의 값을 Update한다.
- 3(0011)의 인덱스 값을 Update하고 최하위 비트(0001)를 더한다. => 4(0010)
- 4(0100)의 인덱스 값을 Update하고 최하위 비트(0100)를 더한다. => 8(1000)
- 8(1000)의 인덱스 값을 Update하고 최하위 비트(1000)를 더한다. => 16
- 16은 Tree의 Index를 벗어아니까 종료한다.
시간 복잡도
Query => O(logN)
Update => O(logN)
문제
2042번: 구간 합 구하기
첫째 줄에 수의 개수 N(1 ≤ N ≤ 1,000,000)과 M(1 ≤ M ≤ 10,000), K(1 ≤ K ≤ 10,000) 가 주어진다. M은 수의 변경이 일어나는 횟수이고, K는 구간의 합을 구하는 횟수이다. 그리고 둘째 줄부터 N+1번째 줄
www.acmicpc.net
코드
#include <bits/stdc++.h>
using namespace std;
vector<long long> ve, tree;
void update(int index, long long diff) {
while (index < tree.size()) {
tree[index] += diff;
index += (index & -index);
}
}
long long query(int index) {
long long result = 0L;
while (index > 0) {
result += tree[index];
index -= (index & -index);
}
return result;
}
int main() {
ios::sync_with_stdio(false); cin.tie(nullptr); cout.tie(nullptr);
int n, m, k;
cin >> n >> m >> k;
ve.resize(n + 1);
tree.resize(n + 1);
for (int i = 1;i <= n;++i) {
cin >> ve[i];
update(i, ve[i]);
}
for (int i = 0;i < m + k;++i) {
int a;
cin >> a;
if (a == 1) {
int b;
long long c;
cin >> b >> c;
update(b, c - ve[b]);
ve[b] = c;
} else {
int b, c;
cin >> b >> c;
cout << query(c) - query(b - 1) << "\n";
}
}
}