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

 

2042번: 구간 합 구하기

첫째 줄에 수의 개수 N(1 ≤ N ≤ 1,000,000)과 M(1 ≤ M ≤ 10,000), K(1 ≤ K ≤ 10,000) 가 주어진다. M은 수의 변경이 일어나는 회수이고, K는 구간의 합을 구하는 회수이다. 그리고 둘째 줄부터 N+1번째 줄까지 N개의 수가 주어진다. 그리고 N+2번째 줄부터 N+M+K+1번째 줄까지 세 개의 정수 a, b, c가 주어지는데, a가 1인 경우 b번째 수를 c로 바꾸고 a가 2인 경우에는 b번째 수부터 c번째 수까지의

www.acmicpc.net

 

[JAVA]

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.StringTokenizer;

public class Main {

    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        StringTokenizer st = new StringTokenizer(br.readLine());
        int n, m, k;
        n = Integer.parseInt(st.nextToken());
        m = Integer.parseInt(st.nextToken());
        k = Integer.parseInt(st.nextToken());
        long a[] = new long[n];
        int h = (int) Math.ceil(Math.log10(n) / Math.log10(2));
        int tree_size = (1 << (h + 1));
        long tree[] = new long[tree_size];
        m += k;
        for (int i = 0; i < n; i++) {
            a[i] = Integer.parseInt(br.readLine());
        }
        init(a, tree, 1, 0, n - 1);

        StringBuilder sb = new StringBuilder();
        while (m-- > 0) {
            int t1, t2, t3;
            st = new StringTokenizer(br.readLine());
            t1 = Integer.parseInt(st.nextToken());
            if (t1 == 1) {
                long t4;
                t2 = Integer.parseInt(st.nextToken());
                t4 = Long.parseLong(st.nextToken());
                t2 -= 1;
                long diff = t4 - a[t2];
                a[t2] = t4;
                update(tree, 1, 0, n - 1, t2, diff);
            } else if (t1 == 2) {
                t2 = Integer.parseInt(st.nextToken());
                t3 = Integer.parseInt(st.nextToken());
                sb.append(sum(tree, 1, 0, n - 1, t2 - 1, t3 - 1) + "\n");
            }
        }
        System.out.println(sb);
        br.close();
    }

    static long init(long[] a, long[] tree, int node, int start, int end) {
        if (start == end)
            return tree[node] = a[start];
        else
            return tree[node] = init(a, tree, node * 2, start, (start + end) / 2)
                    + init(a, tree, node * 2 + 1, (start + end) / 2 + 1, end);
    }

    static void update(long[] tree, int node, int start, int end, int index, long diff) {
        if (index < start || index > end)
            return;
        tree[node] = tree[node] + diff;
        if (start != end) {
            update(tree, node * 2, start, (start + end) / 2, index, diff);
            update(tree, node * 2 + 1, (start + end) / 2 + 1, end, index, diff);
        }
    }

    static long sum(long[] tree, int node, int start, int end, int left, int right) {
        if (left > end || right < start)
            return 0;
        if (left <= start && end <= right)
            return tree[node];
        return sum(tree, node * 2, start, (start + end) / 2, left, right)
                + sum(tree, node * 2 + 1, (start + end) / 2 + 1, end, left, right);
    }

}

 

 

 


 

 

세그먼트 트리 (Segment Tree)

문제 배열 A가 있고, 여기서 다음과 같은 두 연산을 수행해야하는 문제를 생각해봅시다. 구간 l, r (l ≤ r)이 주어졌을 때, A[l] + A[l+1] + ... + A[r-1] + A[r]을 구해서 출력하기 i번째 수를 v로 바꾸기. A[i] = v 수행해야하는 연산은 최대 M번입니다. 세그먼트 트리나 다른 방법을 사용하지 않고 문제를 푼다면, 1번 연산을 수행하는데 O(N), 2번 연산을 수행하는데 O(1)이 걸리게 됩니다. 총 시간 복잡도는 O

www.acmicpc.net

 

'알고리즘 ' 카테고리의 다른 글

SCC - Tarjan (타잔 알고리즘)  (0) 2019.07.11
[알고스팟] WILDCARD - JAVA  (0) 2019.06.06
백준 1941 : 소문난 칠공주  (0) 2019.05.21
SCC - kosaraju  (0) 2019.05.21
Union-Find (유니온 파인드)  (0) 2019.05.17

+ Recent posts