https://www.acmicpc.net/problem/17353
&Title
17353번 - 하늘에서 떨어지는 1, 2, ..., R-L+1개의 별
&Question
욱제의 은밀한 취미 중 하나는 매일 밤하늘을 감상하는
것이다. 😓 욱제는 하늘의 별들이 다음과 같은 규칙들을 따르며
떨어지는 걸 관찰했다.별이 떨어지는 위치는 N개의 점이다. 점은 순서대로
1, 2, ..., N의 번호를 갖는다.매일 밤 별들은 1,
2, ..., N의 연속한 부분 구간 [L, R]에 떨어진다.[L,
R]에 별이 떨어지면, 각 점에는 순서대로 1, 2, ...,
R-L+1개의 별이 떨어진다. 다시 말해, L에는 1개, L+1에는 2개,
..., R에는 R-L+1개의 별이 떨어진다.욱제는 하늘에서 떨어지는 별들을 기록하다가
잠이 들어버렸다!! 혹시나 했지만 역시나, 여러분은 욱제를 대신해 아래의
쿼리를 수행해야 한다. (ㅎㅎ;; ㅈㅅ.. ㅋㅋ!!)1 L R: [L,
R]에 별이 떨어진다. (1 ≤ L ≤ R ≤
N)2 X: 점 X에 떨어진 별의 개수의 합을 출력한다.
(1 ≤ X ≤ N)
&Input
첫째 줄에 별이 떨어지는 점의 개수 N이 주어진다.
(1 ≤ N ≤ 105)둘째 줄에 욱제가 잠들기 전까지
세어 놓은, 이미 떨어진 별들의 개수 A1, ..., AN이
공백을 사이에 두고 주어진다. (0 ≤ A1, ..., AN
≤ 106)셋째 줄에는 쿼리의 개수 Q가 주어진다. (1 ≤
Q ≤ 105)넷째 줄부터 Q개의 줄에는 쿼리가 한 줄에
하나씩 주어진다.
&Output
2번 쿼리에 대한 답을 한 줄에 하나씩 출력한다.
&Example
-input
5
1 2 1 2 1
4
1 1 5
2 5
1 2 5
2 5
-output
6
10
요약
욱제는 밤하늘의 별을 새다가 잠들어 버렸다. 욱제 대신 쿼리를 처리하여 별의 개수를 구하자.
1 L R: [L, R]에 별이 떨어진다. (1 ≤ L ≤ R ≤ N)
2 X: 점 X에 떨어진 별의 개수의 합을 출력한다. (1 ≤ X ≤ N)
L, R 사이의 떨어지는 별은 1, 2, …, R-L+1개가 각각 떨어진다.
접근
매번 전체 업데이트하면 시간 초과 날거 같으니깐 세그먼트트리 lazy propagation을 이용하여 업데이트 해준다.
풀이
먼저 업데이트 함수를 보자 해당 구간인 경우 start - left + 1의 값을 더해주고, 갯수를 증가시켜준다. 즉 3~5구간을 업데이트 할때, 3, 4~5에 대해서 저런 식을 업데이트 해주는 것이다. start - left + 1이 의미하는 것은 3인경우는 start - left = 0이라 상관없지만, 4~5인경우는 start - left가 1이다. 즉 해당 범위에 대한 최소 숫자를 업데이트를 해주고, 나머지 4, 5에 대한 처리는 cnt++을 통해 query할때 연산하게끔 하는거다.
void update(int index, int left, int right, int start, int end) {
if (left > end || right < start)
return;
if (left <= start && end <= right) {
tree[index].val += start - left + 1;
tree[index].cnt++;
}
else {
int mid = (start + end) / 2;
update(index * 2, left, right, start, mid);
update(index * 2 + 1, left, right, mid + 1, end);
}
}
리프노드인 경우는 이미 앞에 start - left + 1식에서 더해질 만큼 더해졌기 때문에 값만 넘겨준다. 이제 양쪽 쿼리를 더해주는데, tree[index].val + tree[index].cnt * (target - start) 이 부분이 핵심이 되시겠다. 해당 숫자의 cnt*(target - start)를 더해주어 결국 target - left + 1의 값을 더한거나 다름없기 쿼리를 하게 된다.
long long query(int index, int target, int start, int end) {
if (target < start || target > end)
return 0;
if (start == end) {
return tree[index].val;
}
else {
int mid = (start + end) / 2;
return query(index * 2, target, start, mid) +
query(index * 2 + 1, target, mid + 1, end) +
tree[index].val + tree[index].cnt * (target - start);
}
}
틀렸던 이유
L, R 사이의 떨어지는 별이 R-L+1이라고 보고 개꽁문제네? 하고 신나게 풀다가 틀렸다… 쩝
댓글남기기