반응형

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

 

11658번: 구간 합 구하기 3

첫째 줄에 표의 크기 N과 수행해야 하는 연산의 수 M이 주어진다. (1 ≤ N ≤ 1024, 1 ≤ M ≤ 100,000) 둘째 줄부터 N개의 줄에는 표에 채워져있는 수가 1행부터 차례대로 주어진다. 다음 M개의 줄에는

www.acmicpc.net

 

 

[ 문제풀이 ]

이 문제를 풀기 전에 다음 글을 먼저 읽고 오시는 것을 추천드립니다.

https://rudalsd.tistory.com/51

 

[ 자료구조 ] 세그먼트 트리 (Segment Tree)

1. 세그먼트 트리 (Segment Tree) 먼저, 세그먼트 트리가 무엇인지 알아봅시다! 세그먼트 트리는 구간 합을 저장하기 위한 트리입니다. 예를 들어 size가 5인 배열이 있다고 생각해봅시다. int arr [5] = {1

rudalsd.tistory.com

 

1. 이 문제를 풀기 위해서 2차원 세그먼트 트리를 만듭니다. (segTree [ x ][ y ])

 

2. segTree[ x ]의 리프노드에 x행의 값들을 다시 세그먼트 트리의 형식으로 저장합니다.

 

[출처] https://m.blog.naver.com/PostView.naver?isHttpsRedirect=true&blogId=jh20s&logNo=221351546136

 

3. 특정 좌표의 값을 업데이트할 때 x행의 세그먼트 트리 노드를 찾은 후 y열의 세그먼트 트리 노드 값을 바꿔줍니다.

 

4. 구간 합을 구할 때도 3과 마찬가지로 x행의 세그먼트 트리 노드를 찾은 후 y열의 세그먼트 트리 노드의 구간합을 구해줍니다.

 

[ 소스코드 ]

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
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
#include<iostream>
 
using namespace std;
 
int N, M;
int segTree[2050][2050];
int arr[1025][1025];
 
void updateTreeY(int node, int s, int e, int x, int y, int diff)
{
    if (y < s || e < y) return;
    segTree[x][node] += diff;
 
    if (s != e) {
        int m = (s + e) / 2;
        updateTreeY(node * 2, s, m, x, y, diff);
        updateTreeY(node * 2+1, m+1, e, x, y, diff);
    }
}
 
void updateTreeX(int node, int s, int e, int x, int y, int diff)
{
    if (x < s || e < x) return;
    updateTreeY(11, N, node, y, diff);
 
    if (s != e) {
        int m = (s + e) / 2;
        updateTreeX(node * 2, s, m, x, y, diff);
        updateTreeX(node * 2 + 1, m + 1, e, x, y, diff);
    }
}
 
int sumTreeY(int node, int s, int e, int x, int y1, int y2)
{
    if (y2 < s || e < y1) return 0;
    if (y1 <= s && e <= y2) return segTree[x][node];
 
    int m = (s + e) / 2;
    int left = sumTreeY(node * 2, s, m, x, y1, y2);
    int right = sumTreeY(node * 2 + 1, m + 1, e, x, y1, y2);
 
    return left + right;
}
 
int sumTreeX(int node, int s, int e, int x1, int y1, int x2, int y2)
{
    if (x2 < s || e < x1) return 0;
    if (x1 <= s && e <= x2) return sumTreeY(11, N, node, y1, y2);
 
    int m = (s + e) / 2;
    int left = sumTreeX(node * 2, s, m, x1, y1, x2, y2);
    int right = sumTreeX(node * 2 + 1, m + 1, e, x1, y1, x2, y2);
 
    return left + right;
}
 
int main()
{
    scanf("%d %d"&N, &M);
 
    for (int i = 1; i <= N; i++) {
        for (int j = 1; j <= N; j++) {
            scanf("%d"&arr[i][j]);
            updateTreeX(11, N, i, j, arr[i][j]);
        }
    }
 
    for (int i = 0; i < M; i++) {
        int w;
        scanf("%d"&w);
 
        if (w == 0) {
            int x, y, c;
            scanf("%d %d %d"&x, &y, &c);
            int diff = c - arr[x][y];
            arr[x][y] = c;
            updateTreeX(11, N, x, y, diff);
        }
        else {
            int ans = 0;
            int x1, y1, x2, y2;
            scanf("%d %d %d %d"&x1, &y1, &x2, &y2);
            printf("%d\n", sumTreeX(11, N, x1, y1, x2, y2));
        }
    }
}
cs
반응형
반응형

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

 

3770번: 대한민국

입력의 첫째 줄에는 테스트 케이스의 개수 T가 주어진다. 각 테스트 케이스의 첫째 줄에는 N, M, K가 주어진다. K는 고속도로의 수이다. 둘째 줄부터 K개의 줄에는 고속도로의 정보가 주어진다. 고

www.acmicpc.net

 

 

[ 문제풀이 ]

이 문제를 풀기 전에 다음 글을 먼저 읽고 오시는 것을 추천드립니다.

https://rudalsd.tistory.com/51

 

[ 자료구조 ] 세그먼트 트리 (Segment Tree)

1. 세그먼트 트리 (Segment Tree) 먼저, 세그먼트 트리가 무엇인지 알아봅시다! 세그먼트 트리는 구간 합을 저장하기 위한 트리입니다. 예를 들어 size가 5인 배열이 있다고 생각해봅시다. int arr [5] = {1

rudalsd.tistory.com

 

1. pair < int, int > arr [ 400001 ]를 만들어 수를 입력받고, arr배열을 오름차순으로 정렬합니다.

 

2. for문을 통해 반복하면서 arr[ i ].second를 idx로 세그먼트 트리를 갱신하고, arr [ i ].second + 1부터 M까지의 구간 합을 구해 ans에 더해줍니다.

 

3. ans를 출력합니다.

 

[ 소스코드 ]

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
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
#include<iostream>
#include<algorithm>
#define ll long long
 
using namespace std;
 
int T;
pair<intint> arr[400001];
 
void updateTree(int node, int s, int e, int idx, ll* segTree)
{
    if (idx < s || e < idx) return;
    segTree[node]++;
 
    if (s != e) {
        int m = (s + e) / 2;
        updateTree(node * 2, s, m, idx, segTree);
        updateTree(node * 2 + 1, m + 1, e, idx, segTree);
    }
}
 
ll sumTree(int node, int s, int e, int sidx, int eidx, ll* segTree)
{
    if (sidx > e || eidx < s) return 0;
    if (sidx <= s && e <= eidx) return segTree[node];
 
    int m = (s + e) / 2;
    ll left = sumTree(node * 2, s, m, sidx, eidx, segTree);
    ll right = sumTree(node * 2 + 1, m + 1, e, sidx, eidx, segTree);
 
    return left + right;
}
 
int main()
{
    scanf("%d"&T);
 
    for (int t = 1; t <= T; t++) {
        int N, M, K;
        ll segTree[2050= { 0 };
        scanf("%d %d %d"&N, &M, &K);
 
        for (int i = 0; i < K; i++) {
            scanf("%d %d"&arr[i].first, &arr[i].second);
        }
 
        sort(arr, arr + K);
 
        ll ans = 0;
 
        for (int i = 0; i < K; i++) {
            updateTree(11, M, arr[i].second, segTree);
            ans += sumTree(11, M, arr[i].second + 1, M, segTree);
        }
 
        printf("Test case %d: %lld\n", t, ans);
    }
}
cs
반응형
반응형

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

 

9463번: 순열 그래프

첫째 줄에 테스트 케이스의 개수 T가 주어진다. 각 테스트 케이스의 첫째 줄에는 n이 주어진다. 둘째 줄과 셋째 줄에는 두 순열이 주어진다. 순열은 {1, 2, ..., n}으로 이루어져 있고, 공백으로 구분

www.acmicpc.net

 

 

[ 문제풀이 ]

이 문제를 풀기 전에 다음 글을 먼저 읽고 오시는 것을 추천드립니다.

https://rudalsd.tistory.com/51

 

[ 자료구조 ] 세그먼트 트리 (Segment Tree)

1. 세그먼트 트리 (Segment Tree) 먼저, 세그먼트 트리가 무엇인지 알아봅시다! 세그먼트 트리는 구간 합을 저장하기 위한 트리입니다. 예를 들어 size가 5인 배열이 있다고 생각해봅시다. int arr [5] = {1

rudalsd.tistory.com

 

1. 첫 줄의 num을 입력받고, arr [ num ] = i로 저장합니다.

 

2. 두 번째 줄의 num을 입력받고, arr [ num ]을 idx로 세그먼트 트리를 갱신합니다.

 

3. arr [ num ] + 1부터 n까지 구간 합을 ans에 더해줍니다.

 

4. ans를 출력합니다.

 

[ 소스코드 ]

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
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
#include<iostream>
#define ll long long
 
using namespace std;
 
int T;
ll segTree[263000];
int arr[100001];
 
void updateTree(int node, int s, int e, int idx)
{
    if (s > idx || e < idx) return;
    segTree[node]++;
 
    if (s != e) {
        int m = (s + e) / 2;
        updateTree(node * 2, s, m, idx);
        updateTree(node * 2 + 1, m + 1, e, idx);
    }
}
 
ll sumTree(int node, int s, int e, int sidx, int eidx)
{
    if (s > eidx || e < sidx) return 0;
    if (sidx <= s && e <= eidx) return segTree[node];
 
    int m = (s + e) / 2;
    ll left = sumTree(node * 2, s, m, sidx, eidx);
    ll right = sumTree(node * 2 + 1, m + 1, e, sidx, eidx);
 
    return left + right;
}
 
int main()
{
    scanf("%d"&T);
 
    for (int t = 0; t < T; t++) {
        int n;
        scanf("%d"&n);
        fill_n(segTree, 2630000);
        
        for (int i = 1; i <= n; i++) {
            int num;
            scanf("%d"&num);
            arr[num] = i;
        }
 
        ll ans = 0;
 
        for (int i = 1; i <= n; i++) {
            int num;
            scanf("%d"&num);
            updateTree(11, n, arr[num]);
            ans += sumTree(11, n, arr[num] + 1, n);
        }
 
        printf("%lld\n", ans);
    }
}
cs
반응형
반응형

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

 

10090번: Counting Inversions

A permutation of integers from 1 to n is a sequence a1, a2, ..., an, such that each integer from 1 to n is appeared in the sequence exactly once. Two integers in а permutation form an inversion, when the bigger one is before the smaller one. As an example

www.acmicpc.net

 

 

[ 문제풀이 ]

이 문제를 풀기 전에 다음 글을 먼저 읽고 오시는 것을 추천드립니다.

https://rudalsd.tistory.com/51

 

[ 자료구조 ] 세그먼트 트리 (Segment Tree)

1. 세그먼트 트리 (Segment Tree) 먼저, 세그먼트 트리가 무엇인지 알아봅시다! 세그먼트 트리는 구간 합을 저장하기 위한 트리입니다. 예를 들어 size가 5인 배열이 있다고 생각해봅시다. int arr [5] = {1

rudalsd.tistory.com

 

1. 입력받은 수를 인덱스로 segment tree를 업데이트합니다.

 

2. 입력받은 수 + 1부터 N까지 구간 합을 ans에 더해줍니다.

 

3. ans를 출력합니다.

 

[ 소스코드 ]

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
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
#include<iostream>
#define ll long long
 
using namespace std;
 
int N;
ll segTree[2100000];
 
void updateTree(int node, int s, int e, int idx)
{
    if (s > idx || e < idx) return;
    segTree[node]++;
 
    if (s != e) {
        int m = (s + e) / 2;
        updateTree(node * 2, s, m, idx);
        updateTree(node * 2 + 1, m + 1, e, idx);
    }
}
 
ll sumTree(int node, int s, int e, int sidx, int eidx)
{
    if (s > eidx || e < sidx) return 0;
    if (sidx <= s && e <= eidx) return segTree[node];
 
    int m = (s + e) / 2;
    ll left = sumTree(node * 2, s, m, sidx, eidx);
    ll right = sumTree(node * 2 + 1, m + 1, e, sidx, eidx);
 
    return left + right;
}
 
int main()
{
    scanf("%d"&N);
 
    ll ans = 0;
 
    for (int i = 0; i < N; i++) {
        int n;
        scanf("%d"&n);
 
        updateTree(11, N, n);
        ans += sumTree(11, N, n + 1, N);
    }
 
    printf("%lld", ans);
}
cs
반응형
반응형

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

 

1615번: 교차개수세기

첫 줄에 N과 간선의 개수 M이 주어진다. 그 다음 줄부터 M+1번째 줄까지 두 개의 수(i, j)가 주어지는데 이는 왼쪽 그룹의 i번 정점과 오른쪽 그룹의 j번 정점을 연결하는 간선이 있다는 의미이다.

www.acmicpc.net

 

 

[ 문제풀이 ]

이 문제를 풀기 전에 다음 글을 먼저 읽고 오시는 것을 추천드립니다.

https://rudalsd.tistory.com/51

 

[ 자료구조 ] 세그먼트 트리 (Segment Tree)

1. 세그먼트 트리 (Segment Tree) 먼저, 세그먼트 트리가 무엇인지 알아봅시다! 세그먼트 트리는 구간 합을 저장하기 위한 트리입니다. 예를 들어 size가 5인 배열이 있다고 생각해봅시다. int arr [5] = {1

rudalsd.tistory.com

 

1. 입력받은 수를 첫번 째 수를 기준으로 오름차순으로 정렬합니다.

 

2. for문을 통해 반복하면서 두번 째 수를 인덱스로 segment tree를 업데이트 합니다.

 

3. 이후 두번 째 수부터 N까지 구간 합을 ans에 더해줍니다.

 

4. ans를 출력합니다.

 

[ 소스코드 ]

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
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
#include<iostream>
#include<algorithm>
#define ll long long
 
using namespace std;
 
int N, M;
pair<intint> arr[2000000];
ll segTree[5000];
 
void updateTree(int node, int s, int e, int idx)
{
    if (s > idx || e < idx) return;
    segTree[node] += 1;
 
    if (s != e) {
        int m = (s + e) / 2;
        updateTree(node * 2, s, m, idx);
        updateTree(node * 2 + 1, m + 1, e, idx);
    }
}
 
ll sumTree(int node, int s, int e, int sidx, int eidx)
{
    if (s > eidx || e < sidx) return 0;
    if (sidx <= s && e <= eidx) return segTree[node];
 
    int m = (s + e) / 2;
    ll left = sumTree(node * 2, s, m, sidx, eidx);
    ll right = sumTree(node * 2 + 1, m + 1, e, sidx, eidx);
 
    return left + right;
}
 
int main()
{
    scanf("%d %d"&N, &M);
 
    for (int i = 0; i < M; i++) {
        scanf("%d %d"&arr[i].first, &arr[i].second);
    }
 
    sort(arr, arr + M);
 
    ll ans = 0;
 
    for (int i = 0; i < M; i++) {
        int cur = arr[i].second;
        
        updateTree(11, N, cur);
        ans += sumTree(11, N, cur + 1, N);
    }
 
    printf("%lld", ans);
}
cs
반응형
반응형

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

 

1777번: 순열복원

순열의 크기 N(1 ≤ N ≤ 100,000)이 주어진다. 두 번째 줄에는 순열 1, 2, …, N에 해당하는 Inversion sequence가 공백으로 구분되어 들어온다.

www.acmicpc.net

 

 

[ 문제풀이 ]

이 문제를 풀기 전에 다음 글을 먼저 읽고 오시는 것을 추천드립니다.

https://rudalsd.tistory.com/51

 

[ 자료구조 ] 세그먼트 트리 (Segment Tree)

1. 세그먼트 트리 (Segment Tree) 먼저, 세그먼트 트리가 무엇인지 알아봅시다! 세그먼트 트리는 구간 합을 저장하기 위한 트리입니다. 예를 들어 size가 5인 배열이 있다고 생각해봅시다. int arr [5] = {1

rudalsd.tistory.com

 

1. 모든 리프 노드를 1로 초기화시킵니다.

 

2. 각 숫자의 값은 큰 숫자부터 뒤의 빈칸의 수를 의미합니다. 따라서, 세그먼트 트리의 노드의 값이 빈칸의 수를 의미하고, 이 수가 현재 숫자의 값보다 크다면 해당 노드로, 작다면 노드의 값을 뺀 값을 가지고 다음 노드로 재귀합니다.

 

3. 리프노드에 도달하면 해당 위치에 현재 숫자가 있는 것이므로 ans [해당 위치] = 현재 숫자가 됩니다.

 

4. for문을 통해 1부터 N번 째 위치까지의 수를 출력합니다.

 

[ 소스코드 ]

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
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
#include<iostream>
 
using namespace std;
 
int N;
int arr[100001];
int ans[100001];
int segTree[263000];
 
void makeTree(int node, int s, int e)
{
    if (s == e) {
        segTree[node] = 1;
        return;
    }
 
    int m = (s + e) / 2;
    makeTree(node * 2, s, m);
    makeTree(node * 2 + 1, m + 1, e);
 
    segTree[node] = segTree[node * 2+ segTree[node * 2 + 1];
}
 
void updateTree(int node, int s, int e, int x, int i)
{
    segTree[node] -= 1;
 
    if (s == e) {
        ans[s] = i;
        return;
    }
 
    int m = (s + e) / 2;
    if (segTree[node * 2 + 1< x) {
        updateTree(node * 2, s, m, x - segTree[node * 2 + 1], i);
    }
    else {
        updateTree(node * 2 + 1, m + 1, e, x, i);
    }
}
 
int main()
{
    scanf("%d"&N);
 
    for (int i = 1; i <= N; i++) {
        scanf("%d"&arr[i]);
    }
 
    makeTree(11, N);
 
    for (int i = N; i > 0 ; i--) {
        updateTree(11, N, arr[i] + 1, i);
    }
 
    for (int i = 1; i <= N; i++) {
        printf("%d ", ans[i]);
    }
}
cs
반응형
반응형

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

 

1849번: 순열

1부터 N까지의 수들이 한 번씩 쓰인 수열이 있다. 그 수열에서 i 앞에 있는 수 들 중, i보다 큰 수들의 개수를 A[i]라고 정의하자. A[i]가 주어져 있을 때, 원래 수열을 구하는 프로그램을 작성하여라

www.acmicpc.net

 

 

[ 문제풀이 ]

이 문제를 풀기 전에 다음 글을 먼저 읽고 오시는 것을 추천드립니다.

https://rudalsd.tistory.com/51

 

[ 자료구조 ] 세그먼트 트리 (Segment Tree)

1. 세그먼트 트리 (Segment Tree) 먼저, 세그먼트 트리가 무엇인지 알아봅시다! 세그먼트 트리는 구간 합을 저장하기 위한 트리입니다. 예를 들어 size가 5인 배열이 있다고 생각해봅시다. int arr [5] = {1

rudalsd.tistory.com

 

1. 모든 리프 노드를 1로 초기화시킵니다.

 

2. 각 숫자의 값은 작은 숫자부터 앞의 빈칸의 수를 의미합니다. 따라서, 세그먼트 트리의 노드의 값이 빈칸의 수를 의미하고, 이 수가 현재 숫자의 값보다 크다면 해당 노드로, 작다면 노드의 값을 뺀 값을 가지고 다음 노드로 재귀합니다.

 

3. 리프노드에 도달하면 해당 위치에 현재 숫자가 있는 것이므로 ans [해당 위치] = 현재 숫자가 됩니다.

 

4. for문을 통해 1부터 N번 째 위치까지의 수를 출력합니다.

 

[ 소스코드 ]

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
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
#include<iostream>
 
using namespace std;
 
int N;
int arr[100001];
int segTree[263000];
int ans[100001];
 
void makeTree(int node, int s, int e)
{
    if (s == e) {
        segTree[node] = 1;
        return;
    }
 
    int m = (s + e) / 2;
    makeTree(node * 2, s, m);
    makeTree(node * 2 + 1, m+1, e);
 
    segTree[node] = segTree[node * 2+ segTree[node * 2 + 1];
}
 
void getTree(int node, int s, int e, int x, int i)
{
    if (s == e) {
        segTree[node] = 0;
        ans[s] = i;
        return;
    }
 
    segTree[node] -= 1;
 
    int m = (s + e) / 2;
    if (segTree[node * 2< x) {
        getTree(node * 2 + 1, m + 1, e, x - segTree[node * 2], i);
    }
    else {
        getTree(node * 2, s, m, x, i);
    }
}
 
int main()
{
    scanf("%d"&N);
    
    for (int i = 1; i <= N; i++) {
        scanf("%d"&arr[i]);
    }
 
    makeTree(11, N);
 
    for (int i = 1; i <= N; i++) {
        getTree(11, N, arr[i] + 1, i);
    }
 
    for (int i = 1; i <= N; i++) {
        printf("%d\n", ans[i]);
    }
}
cs
반응형
반응형

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

 

 

[ 문제풀이 ]

이 문제를 풀기 전에 다음 글을 먼저 읽고 오시는 것을 추천드립니다.

https://rudalsd.tistory.com/256

 

[ 자료구조 ] 느리게 갱신되는 세그먼트 트리 (Lazy Propagation)

https://rudalsd.tistory.com/51 [ 자료구조 ] 세그먼트 트리 (Segment Tree) 1. 세그먼트 트리 (Segment Tree) 먼저, 세그먼트 트리가 무엇인지 알아봅시다! 세그먼트 트리는 구간 합을 저장하기 위한 트리입니다.

rudalsd.tistory.com

 

1. 세그먼트 트리와 lazy값을 저장할 배열을 만듭니다.

 

2. 느리게 갱신되는 세그먼트 트리를 활용하여 Update를 하고 원하는 인덱스의 값을 출력합니다.

 

[ 소스코드 ]

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
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
#include<iostream>
#define ll long long
 
using namespace std;
 
int N, M;
ll arr[100001];
ll segTree[263000];
ll lazy[263000];
 
void makeTree(int node, int start, int end)
{
    if (start == end) {
        segTree[node] = arr[start];
        return;
    }
 
    int mid = (start + end/ 2;
    makeTree(node * 2, start, mid);
    makeTree(node * 2 + 1, mid + 1end);
 
    segTree[node] = segTree[node * 2+ segTree[node * 2 + 1];
}
 
void modifyLazy(int node, int start, int end)
{
    if (lazy[node] != 0) {
        segTree[node] += (ll)(end - start + 1* lazy[node];
 
        if (start != end) {
            lazy[node * 2+= lazy[node];
            lazy[node * 2 + 1+= lazy[node];
        }
 
        lazy[node] = 0;
    }
}
 
void modifyTree(int node, int start, int endint i, int j, ll k)
{
    modifyLazy(node, start, end);
 
    if (start > j || end < i) return;
 
    if (i <= start && end <= j) {
        lazy[node] += k;
        modifyLazy(node, start, end);
 
        return;
    }
 
    int mid = (start + end/ 2;
    modifyTree(node * 2, start, mid, i, j, k);
    modifyTree(node * 2 + 1, mid + 1end, i, j, k);
 
    segTree[node] = segTree[node * 2+ segTree[node * 2 + 1];
}
 
void getTree(int node, int start, int endint x)
{
    modifyLazy(node, start, end);
 
    if (start > x || x > endreturn;
    if (start == end) {
        arr[start] = segTree[node];
        return;
    }
 
    int mid = (start + end/ 2;
    getTree(node * 2, start, mid, x);
    getTree(node * 2 + 1, mid + 1end, x);
}
 
int main()
{
    scanf("%d"&N);
 
    for (int i = 1; i <= N; i++) {
        scanf("%lld"&arr[i]);
    }
 
    makeTree(11, N);
 
    scanf("%d"&M);
 
    for (int m = 0; m < M; m++) {
        int cmd;
        scanf("%d"&cmd);
 
        if (cmd == 1) {
            int i, j;
            ll k;
            scanf("%d %d %lld"&i, &j, &k);
            modifyTree(11, N, i, j, k);
        }
        else {
            int x;
            scanf("%d"&x);
            getTree(11, N, x);
 
            printf("%lld\n", arr[x]);
        }
    }
}
cs
반응형
반응형

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은 수의 변경이 일어나는 횟수이고, K는 구간의 합을 구하는 횟수이다. 그리고 둘째 줄부터 N+1번째 줄

www.acmicpc.net

 

 

[ 문제풀이 ]

이 문제를 풀기 전에 다음 글을 먼저 읽고 오시는 것을 추천드립니다.

https://rudalsd.tistory.com/256

 

[ 자료구조 ] 느리게 갱신되는 세그먼트 트리 (Lazy Propagation)

https://rudalsd.tistory.com/51 [ 자료구조 ] 세그먼트 트리 (Segment Tree) 1. 세그먼트 트리 (Segment Tree) 먼저, 세그먼트 트리가 무엇인지 알아봅시다! 세그먼트 트리는 구간 합을 저장하기 위한 트리입니다.

rudalsd.tistory.com

 

1. 세그먼트 트리와 lazy값을 저장할 배열을 만듭니다.

 

2. 느리게 갱신되는 세그먼트 트리를 활용하여 Update를 하고 구간 합을 출력합니다.

 

[ 소스코드 ]

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
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
#include<iostream>
#define ll long long
 
using namespace std;
 
int N, M, K;
ll arr[1000001];
ll segTree[2100000];
ll lazy[2100000];    //방문할 필요가 없는 노드의 경우 다음 방문 때 더할 값을 저장
 
void makeTree(int node, int start, int end)
{
    if (start == end) {
        segTree[node] = arr[start];
        return;
    }
 
    int mid = (start + end/ 2;
    makeTree(node * 2, start, mid);
    makeTree(node * 2 + 1, mid + 1end);
 
    segTree[node] = segTree[node * 2+ segTree[node * 2 + 1];
}
 
void modifyLazy(int node, int start, int end)    //현재 노드에 lazy 값이 있다면 더해주기
{
    if (lazy[node] != 0) {
        segTree[node] += (ll)(end - start + 1* lazy[node];
        if (start != end) {    //리프 노드가 아니라면 아래 노드에 lazy값 물려주기
            lazy[node * 2+= lazy[node];
            lazy[node * 2 + 1+= lazy[node];
        }
 
        lazy[node] = 0;
    }
}
 
void modifyTree(int node, int start, int endint sidx, int eidx, ll d)
{
    modifyLazy(node, start, end);    //현재 노드에 lazy값 체크
 
    if (sidx > end || start > eidx) return;
 
    if (sidx <= start && end <= eidx) {    //완전히 포함된다면
        segTree[node] += (ll)(end - start + 1* d;
        if (start != end) {    //리프 노드가 아닐 경우 아래 노드에 lazy값 물려주기
            lazy[node * 2+= d;
            lazy[node * 2 + 1+= d;
        }
        return;
    }
 
    int mid = (start + end/ 2;
    modifyTree(node * 2, start, mid, sidx, eidx, d);
    modifyTree(node * 2 + 1, mid+1end, sidx, eidx, d);
 
    segTree[node] = segTree[node * 2+ segTree[node * 2 + 1];
}
 
ll sumTree(int node, int start, int endint sidx, int eidx)
{
    modifyLazy(node, start, end);    //현재 노드에 lazy값 체크
 
    if (start > eidx || end < sidx) return 0;
    if (sidx <= start && end <= eidx) return segTree[node];
 
    int mid = (start + end/ 2;
    ll left = sumTree(node * 2, start, mid, sidx, eidx);
    ll right = sumTree(node * 2 + 1, mid + 1end, sidx, eidx);
 
    return left + right;
}
 
int main()
{
    scanf("%d %d %d"&N, &M, &K);
 
    for (int i = 1; i <= N; i++) {
        scanf("%lld"&arr[i]);
    }
 
    makeTree(11, N);
 
    for (int i = 0; i < M + K; i++) {
        int a;
        scanf("%d"&a);
 
        if (a == 1) {
            int b, c;
            ll d;
            scanf("%d %d %lld"&b, &c, &d);
 
            modifyTree(11, N, b, c, d);
        }
        else {
            int b, c;
            scanf("%d %d"&b, &c);
 
            printf("%lld\n", sumTree(11, N, b, c));
        }
    }
}
cs
반응형
반응형

https://rudalsd.tistory.com/51

 

[ 자료구조 ] 세그먼트 트리 (Segment Tree)

1. 세그먼트 트리 (Segment Tree) 먼저, 세그먼트 트리가 무엇인지 알아봅시다! 세그먼트 트리는 구간 합을 저장하기 위한 트리입니다. 예를 들어 size가 5인 배열이 있다고 생각해봅시다. int arr [5] = {1

rudalsd.tistory.com

1. 느리게 갱신되는 세그먼트 트리 (Lazy Propagation)

 

Lazy Propagation에서는 각 노드마다 lazy라는 값을 둡다. Lazy Propagation이라는 이름에서 알 수 있듯, 이 자료구조에서는 모든 값을 그때그때 갱신하지 않습니다. 굳이 갱신할 필요가 없는 노드에 대해서 lazy라는 값을 조정해 나중에 이 노드를 방문할 일이 생길 때까지는 갱신을 미루어 시간적 효율을 올리는 것입니다.

 

2. Lazy Propagation 만들기

 

Lazy Propagation을 만드는 방식은 일반적인 세그먼트 트리를 만드는 방식과 똑같습니다.

 

3. Lazy Propagation Update

 

Lazy Propagation에서 값을 수정하는 방법은 다음과 같습니다.

 

Update : 2 - 4 (+10)

Update : 2 - 4 (+10)

Update : 2 - 4 (+10)

Update : 2 - 4 (+10)

Update : 2 - 4 (+10)

Update : 2 - 4 (+10)

이렇게 2-4 구간에 대한 Update는 끝납니다. 일반적인 세그먼트 트리였다면 값이 갱신되는 리프 노드까지 내려갔다가 올라와야 하므로 더 오래 걸리지만 Lazy Propagation을 사용한다면 불필요한 방문을 줄여 훨씬 더 빠르게 갱신이 가능합니다.

 

이후 lazy값이 있는 노드에 방문한다면 노드에 그 값을 적용시키고 아래 노드에 물려줍니다.

 

4. Lazy Propagation 구간합 구하기

 

일반적인 세그먼트 트리와 구간합을 구하는 방식은 동일합니다. 하지만 해당 노드에 lazy값이 있다면 적용시킨 후 값을 더해주면 됩니다.

 

반응형

+ Recent posts