Hanbit the Developer

[C++] 16975번: 수열과 쿼리 21(Lazy Propagation) 본문

Algorithm/백준

[C++] 16975번: 수열과 쿼리 21(Lazy Propagation)

hanbikan 2021. 11. 22. 23:40

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

 

16975번: 수열과 쿼리 21

길이가 N인 수열 A1, A2, ..., AN이 주어진다. 이때, 다음 쿼리를 수행하는 프로그램을 작성하시오. 1 i j k: Ai, Ai+1, ..., Aj에 k를 더한다. 2 x: Ax 를 출력한다.

www.acmicpc.net

 

 - 배경

Segment Tree의 Lazy Propagation을 안다는 전제로 글을 작성하였으니, 해당 개념에 대해서는 다음 링크를 참조하자.

https://rccode.tistory.com/entry/Python-%EB%B0%B1%EC%A4%80-10999%EB%B2%88-%EA%B5%AC%EA%B0%84-%ED%95%A9-%EA%B5%AC%ED%95%98%EA%B8%B0-2

 

[Python] Lazy Propagation (백준 10999번: 구간 합 구하기 2)

https://www.acmicpc.net/problem/10999 10999번: 구간 합 구하기 2 첫째 줄에 수의 개수 N(1 ≤ N ≤ 1,000,000)과 M(1 ≤ M ≤ 10,000), K(1 ≤ K ≤ 10,000) 가 주어진다. M은 수의 변경이 일어나는 횟수이고,..

rccode.tistory.com

 

 - 풀이

일반적인 세그먼트 트리로는 시간복잡도에 걸리므로, Lazy Propagation을 통한 효율적인 풀이를 사용하였다.

느리게 갱신되는 세그먼트 트리의 기본 형태에, query문을 한 개 원소의 영역에 대해서 수행해주기만 하면 된다.

 

#include <iostream>
using namespace std;

long long A[100001];
long long segTree[400004];
long long lazy[400004];

long long initializeSegTree(int index, int start, int end) {
	if (start == end) segTree[index] = A[start];
	else {
		int mid = (start + end) / 2;
		segTree[index] = initializeSegTree(index * 2, start, mid) + 
			initializeSegTree(index*2+1, mid+1, end);
	}

	return segTree[index];
}

void propagateSegTree(int index, int start, int end) {
	if (lazy[index] != 0) {
		if (start != end) {
			lazy[index * 2] += lazy[index];
			lazy[index * 2 + 1] += lazy[index];
		}

		segTree[index] += (end - start + 1) * lazy[index];
		lazy[index] = 0;
	}
}

void updateSegTree(int index, int start, int end, int left, int right, int toAdded) {
	propagateSegTree(index, start, end);

	if (right < start || end < left) return;

	if (left <= start && end <= right) {
		lazy[index] += toAdded;
		propagateSegTree(index, start, end);
		return;
	}

	int mid = (start + end) / 2;
	updateSegTree(index * 2, start, mid, left, right, toAdded);
	updateSegTree(index * 2+1, mid+1, end, left, right, toAdded);
	segTree[index] = segTree[index * 2] + segTree[index * 2 + 1];
}

long long querySegTree(int index, int start, int end, int left, int right) {
	propagateSegTree(index, start, end);

	if (right < start || end < left) return 0;

	if (left <= start && end <= right) return segTree[index];

	int mid = (start + end) / 2;
	return querySegTree(index * 2, start, mid, left, right) +
		querySegTree(index * 2 + 1, mid + 1, end, left, right);
}

int main()
{
	ios::sync_with_stdio(0); cin.tie(0); cout.tie(0);

	int i;

	int N;
	cin >> N;
	for (i = 1; i < N+1; i++) cin >> A[i];

	initializeSegTree(1, 1, N);

	int M;
	cin >> M;
	for (i = 0; i < M; i++) {
		int op;
		cin >> op;
		if (op == 1) {
			int a, b, k;
			cin >> a >> b >> k;
			updateSegTree(1, 1, N, a, b, k);
		}
		else {
			int x;
			cin >> x;
			cout << querySegTree(1, 1, N, x, x) << "\n";
		}
	}
}

'Algorithm > 백준' 카테고리의 다른 글

[C] 백준 10282번: 해킹  (0) 2021.12.15
[C] 백준 2252번: 줄 세우기  (0) 2021.12.14
[C++] 백준 17143번: 낚시왕  (0) 2021.11.20
[C++] 백준 16946번: 벽 부수고 이동하기 4  (0) 2021.11.19
[C++] 백준 5373번: 큐빙  (0) 2021.11.19