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 |