이거때매 하루종일 고생중. x&(-x)가 무엇이냐 부터 힘들었다.
read 연산
int read(int idx)
{
int sum = 0;
while (idx > 0){
sum += tree[idx];
idx -= (idx & -idx);
}
return sum;
}
update 연산
int tree[20];
#define MaxVal 16
void update(int idx ,int val)
{
while (idx <= MaxVal){
tree[idx] += val;
idx += (idx & -idx);
}
}
일단 read가 처음부터 idx까지의 구간 합을 구하는 함수고
update는 idx번째 아이템의 값을 갱신하는 함수이다. 이렇게 되면
read도 log(n), update도 log(n)으로 쿼리가 m개면 m*log(n)으로 해결 된다.
여기서 idx를 갱신할 때 2가지 방법을 쓸 수 있다.
1. x&(-x)
이것은 x의 약수 중 2의 제곱수만 빼면 된다. ex) 4 : 4, 5 : 1, 6 : 2
그러므로 idx -= (idx& -idx) 이런식.
2. x&(x-1)
이것은 x 이하의 수 중 가장 큰 2의 배수를 리턴. ex) 4 : 4, 5 : 4, 6 : 6, 15 : 14
그러므로 idx = (idx&(idx-1))
참고 사이트 : http://59.23.113.171/30stair/bindexedtree/bindexedtree.php?pname=bindexedtree
예제 문제 : https://www.acmicpc.net/problem/2042 - 구간 합치기
가장 전형적인 문제로 BIT를 '사용하기만하면' 풀어진다.
아래는 위 문제의 소스코드
#include <stdio.h>
long long int tr[1000001];
long long int val[1000001];
int n;
long long int read(long long int idx){
long long int sum = 0;
while (idx > 0){
sum += tr[idx];
idx -= (idx & -idx);
}
return sum;
}
void update(long long int idx ,long long int val){
while (idx <= n){
tr[idx] += val;
idx += (idx & -idx);
}
}
int main(){
int m,k;
scanf("%d %d %d",&n,&m,&k);
for(long long int i=1;i<=n;i++){
scanf("%lld",&val[i]);
update(i,val[i]);
}
for(int i=0;i<m+k;i++){
long long int a,b,c;
scanf("%lld %lld %lld",&a,&b,&c);
if(a==1){
update(b,c-val[b]);
val[b] = c;
}
else{
printf("%lld\n",read(c)-read(b-1));
}
}
return 0;
}