티스토리 뷰
#include <stdio.h>
long long int arr[100001]={};
long long int tree[400004]={};
void update(int s, int e, int node, int index, int val) { //segment tree update
if(s > index || e < index) return;
tree[node] += val;
if(s == e) return;
int m = (s+e)/2;
update(s, m, node*2, index, val);
update(m+1, e, node*2+1, index, val);
}
long long int find(int s, int e, int node, int l, int r) { //segment tree에서 부분합 구하기
if(s > r || e < l) return 0;
if(l <= s && e <= r) return tree[node];
int m = (s+e)/2;
return find(s, m, node*2, l, r) + find(m+1, e, node*2+1, l, r);
}
int main(void) {
int n, m;
scanf("%d", &n);
for(int i=1; i<=n; i++) {
scanf("%lld", &arr[i]); //요소들을 입력받고
update(1, n, 1, i, arr[i]); //segment tree update
}
scanf("%d", &m); //쿼리 개수 입력
long long int q[m][4]; //쿼리들을 담을 배열
int left = 0, right = m-1; //0부턴 2번쿼리들을 m-1번에서 부턴 1번쿼리들을 저장
for(int i=0; i<m; i++) { //쿼리입력 및 저장
long long int a, b, c, d;
scanf("%lld", &a);
if(a==1) {
scanf("%lld %lld", &b, &c);
q[right][0] = b;
q[right][1] = c;
right--;
}
else {
scanf("%lld %lld %lld", &b, &c, &d);
q[left][0] = b;
q[left][1] = c;
q[left][2] = d;
q[left][3] = left; //2번쿼리들의 입력을 받은 순서들도 넘겨줍니다. (마지막 순차적 출력을 위해서)
left++;
}
}
int gap = left/2, i, j, key[4];
while(1) { //2번 쿼리 오름차순 정렬 , shell sort
if(gap%2==0) gap++;
for(i=gap; i<left; i++) {
key[0] = q[i][0];
key[1] = q[i][1];
key[2] = q[i][2];
key[3] = q[i][3];
for(j=i-gap; j>=0; j-=gap) {
if(key[0] < q[j][0]) {
q[j+gap][0] = q[j][0];
q[j+gap][1] = q[j][1];
q[j+gap][2] = q[j][2];
q[j+gap][3] = q[j][3];
} else break;
}
q[j+gap][0] = key[0];
q[j+gap][1] = key[1];
q[j+gap][2] = key[2];
q[j+gap][3] = key[3];
}
if(gap == 1) break;
gap >>= 1;
}
long long int ans[left]; //부분합을 담을 배열
int tmp = m-1;
j=0;
for(i=0; i<left; i++) { //순서대로 정렬된 2번쿼리와, 순서대로 저장해 놓은 1번쿼리를 이용하여 부분합을 구한 다음 위에서 만든 배열에 저장해두기
while(q[i][0] > j) { //1번쿼리
update(1, n, 1, q[tmp][0], q[tmp][1]-arr[q[tmp][0]]); //segment tree update
arr[q[tmp][0]] = q[tmp][1];
j++;
tmp--;
}
ans[q[i][3]] = find(1, n, 1, q[i][1], q[i][2]); //2번쿼리
}
for(i=0; i<left; i++) { //2번쿼리를 처음 받았던 순서대로 부분합을 출력해줍니다.
printf("%lld\n", ans[i]);
}
}
풀이 : 세그먼트 트리, 오프라인 쿼리
쿼리의 종류는 2가지 입니다.
1. 배열의 값 중 하나를 바꿉니다.
2. 1.쿼리가 몇번 적용된 이후의 특정 구간에서의 구간합을 구합니다.
여기서 2번 쿼리의 몇번 적용된 이후의 이 부분을 해결하기위해서 쿼리를 입력받자 마자 바로 처리하는 것이 아니라
일단 1번, 2번 쿼리들을 순서대로 각각 저장해 놓은 다음 2번 쿼리를 1번 쿼리가 몇번 적용된 이후에 적용되는지를 가지고 오름차순 정렬을 합니다.
오름차순 정렬을 한 후
2번 쿼리들을 처리하면 됩니다.
만약 2번쿼리를 처리하는데 1번쿼리가 2번쿼리가 요구하는 만큼 적용이 되지 않았다면, 만족할때까지 1번쿼리를 실행하여 세그먼트 트리를 update 하면 됩니다!
이렇게 2번쿼리들에 대한 부분합들을 구했다면,
이러한 부분합들을 2번쿼리들을 처음 입력 받았던 순서에 맞추어서 출력하면 됩니다!
https://www.acmicpc.net/problem/16978
16978번: 수열과 쿼리 22
길이가 N인 수열 A1, A2, ..., AN이 주어진다. 이때, 다음 쿼리를 수행하는 프로그램을 작성하시오. 1 i v: Ai = v로 변경한다. 2 k i j: k번째 1번 쿼리까지 적용되었을 때, Ai, Ai+1, ..., Aj의 합을 출력한다.
www.acmicpc.net
'c언어 > BAEKJOON' 카테고리의 다른 글
c언어 13548번 수열과 쿼리 6 (백준) (0) | 2023.07.14 |
---|---|
c언어 28291번 레드스톤 (백준) (0) | 2023.07.12 |
c언어 13306 트리 (백준) (0) | 2023.07.08 |
c언어 17408번 수열과 쿼리 24 (백준) (0) | 2023.06.29 |
c언어 13398번 연속합 2 (백준) (0) | 2023.06.28 |
공지사항
최근에 올라온 글
최근에 달린 댓글
- Total
- Today
- Yesterday
링크
TAG
- union
- 최소 스패닝 트리
- 스택
- 플로이드
- Lazy Propagation
- C++
- java
- PASCAL
- Krustal
- 정렬
- 브루트포스
- BFS
- 누적합
- 최대공약수
- 그래프
- 1835번
- 오프라인 쿼리
- DFS
- 1835
- 세그먼트 트리
- 그리디
- XOR
- find
- 기하학
- DP
- 덱
- C언어
- 누적 합
- 백준
- Segment Tree
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | ||||
4 | 5 | 6 | 7 | 8 | 9 | 10 |
11 | 12 | 13 | 14 | 15 | 16 | 17 |
18 | 19 | 20 | 21 | 22 | 23 | 24 |
25 | 26 | 27 | 28 | 29 | 30 | 31 |
글 보관함