Skip to content

Latest commit

 

History

History
105 lines (86 loc) · 3.83 KB

세그먼트트리.md

File metadata and controls

105 lines (86 loc) · 3.83 KB

세그먼트트리로 구간합을 구하는 알고리즘이다.

https://www.acmicpc.net/problem/2042

import java.util.*;

public class boj2042{
    static Scanner sc = new Scanner(System.in);
    static long[] Tree;
    static long[] arr;
    
    static int log2(int x,int base){
        return (int) Math.ceil(Math.log10(x)/Math.log10(2));
    }
    
    /*
    makeTree :
    길이가 8인 배열이 있을때
    
                           (1-8의 구간합)
                          /              \
            (1-4의 구간합)               (5-4의 구간합)
           /             \              /             \
    (1-2의 구간합) (3-4의 구간합) (5-6의 구간합) (7-8의 구간합)
      /        \     /        \     /       \     /        \  
    (1)        (2) (3)        (4) (5)       (6) (7)        (8)
    
    재귀함수를 써서 이런 형태로 트리를 만든다. (Tree배열에 1차원으로 저장)
    (배열은 (1-8의 구간합), (1-4의 구간합), (5-4의 구간합), (1-2의 구간합), (3-4의 구간합), (5-6의 구간합)...의 순서로 구성)
    */
    
    static long makeTree(int l, int r, int x){
        if(l==r) Tree[x] = arr[l];
        else Tree[x] = makeTree(l,(l+r)/2,x*2)+makeTree((l+r)/2+1,r,x*2+1);
        return Tree[x];
    }

    /*
    updateTree :
    
                           (1-8의 구간합)
                         //              \
            (1-4의 구간합)               (5-4의 구간합)
           /            \\              /             \
    (1-2의 구간합) (3-4의 구간합) (5-6의 구간합) (7-8의 구간합)
      /        \     /       \\     /       \     /        \  
    (1)        (2) (3)        (4) (5)       (6) (7)        (8)
    
    4를 업데이트 한다고 가정,
    구간을 반으로 쪼개서 4가 왼쪽에 속하는지 오른쪽에 속하는지 판단해서 4가 구간에 포함된 노드를 탐색함
    그리고 4가 포함된 노드들의 바뀔 값-원래값을 더해줌
    */ 
    
    static void updateTree(int l, int r, int x, int goal, long val){
        Tree[x]+=val;
        if(l==r) return;
        if(l<=goal&&goal<=(l+r)/2) updateTree(l,(l+r)/2,x*2,goal,val);
        else if((l+r)/2+1<=goal&&goal<=r) updateTree((l+r)/2+1,r,x*2+1,goal,val);
    }

    /*
    sumTree :
    - 만약에 지금 위치가(지금 범위가) 내가 찾아야 하는 구간에 포함된다 -> 더해줌
    - 만약에 내가 합을 찾아야 하는 구간이 왼쪽의 부분집합이다 -> 왼쪽 탐색
    - 만약에 내가 합을 찾아야 하는 구간이 오른쪽의 부분집합이다 -> 오른쪽 탐색
    - 만약에 왼쪽이랑 오른쪽에 애매하게 겹쳐져있다 -> 왼쪽 오른쪽 쪼개서 탐색
    */
    
    static long sumTree(int l, int r, int x, int gl, long gr){
        if(gl<=l&&r<=gr)return Tree[x];
        else if(gr<=(l+r)/2) return sumTree(l,(l+r)/2,x*2,gl,gr);
        else if((l+r)/2+1<=gl) return sumTree((l+r)/2+1,r,x*2+1,gl,gr);
        else if(gl<=(l+r)/2&&(l+r)/2<=gr)return sumTree(l,(l+r)/2,x*2,gl,gr)+sumTree((l+r)/2+1,r,x*2+1,gl,gr);
        return 0;
    }
    
    public static void main(String[] args){
        int n = sc.nextInt();
        int m = sc.nextInt();
        int k = sc.nextInt();
        arr = new long[n];
        Tree = new long[(int)Math.pow(2,log2(n,2)+1)+1]; 
        
        for(int i = 0; i < n; i++)arr[i] = sc.nextLong();
        makeTree(0,n-1,1);
        
        for(int i = 0; i < m + k; i++){
            int c = sc.nextInt();
            int a = sc.nextInt();
            long b = sc.nextLong();
            
            if(c==1){
                long tmp = arr[a-1];
                arr[a-1] = b; 
                updateTree(0,n-1,1,a-1,b-tmp);
            } else if(c==2) {
                System.out.println(sumTree(0,n-1,1,a-1,b-1));
            }
        }
        sc.close();
    }
}