반응형

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

 

13544번: 수열과 쿼리 3

길이가 N인 수열 A1, A2, ..., AN이 주어진다. 이때, 다음 쿼리를 수행하는 프로그램을 작성하시오. i j k: Ai, Ai+1, ..., Aj로 이루어진 부분 수열 중에서 k보다 큰 원소의 개수를 출력한다.

www.acmicpc.net

 

 

[ 문제풀이 ]

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

https://rudalsd.tistory.com/462

 

[ 자료구조 ] 머지 소트 트리(Merge Sort Tree)

1. 머지 소트 트리(Merge Sort Tree) 머지 소트 트리(Merge Sort Tree)는 분할 정복을 활용하는 합병 정렬(Merge Sort)을 저장하는 자료구조 입니다. 2. 머지 소트 트리(Merge Sort Tree) 동작 원리 머지 소트 트리(Me

rudalsd.tistory.com

 

1. 수열을 입력받고, 머지 소트 트리를 구현합니다.

 

2. a, b, c를 입력받고 pre에 xor 한 후 그 값을 이용하여 해당 구간에 대해 upper_bound를 활용하여, 해당 구간의 값 중 k보다 큰 값을 ans에 저장합니다.

 

3. ans를 출력하고, pre에 ans를 저장한 후 2를 반복해 줍니다.

 

[ 소스코드 ]

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
#include<iostream>
#include<vector>
#include<algorithm>
 
using namespace std;
 
int N, M;
vector<int> mergeSortTree[262222];
int arr[100001];
int ans;
int pre;
 
void merge(int node, int s, int e)
{
    int s_size = mergeSortTree[node * 2].size();
    int e_size = mergeSortTree[node * 2 + 1].size();
    int i = 0, j = 0;
 
    while (1) {
        if (mergeSortTree[node * 2][i] < mergeSortTree[node * 2 + 1][j]) {
            mergeSortTree[node].push_back(mergeSortTree[node * 2][i++]);
        }
        else {
            mergeSortTree[node].push_back(mergeSortTree[node * 2 + 1][j++]);
        }
 
        if (i == s_size || j == e_size) {
            break;
        }
    }
 
    if (i < s_size) {
        for (i; i < s_size; i++) {
            mergeSortTree[node].push_back(mergeSortTree[node * 2][i]);
        }
    }
    else {
        for (j; j < e_size; j++) {
            mergeSortTree[node].push_back(mergeSortTree[node * 2 + 1][j]);
        }
    }
}
 
void makeTree(int node, int s, int e)
{
    if (s == e) {
        mergeSortTree[node].push_back(arr[s]);
        return;
    }
 
    int m = (s + e) / 2;
    makeTree(node * 2, s, m);
    makeTree(node * 2 + 1, m + 1, e);
 
    merge(node, s, e);
}
 
void getTree(int node, int s, int e, int i, int j, int k)
{
    if (s > j || e < i) return;
    if (i <= s && e <= j) {
        ans += mergeSortTree[node].end() - upper_bound(mergeSortTree[node].begin(), mergeSortTree[node].end(), k);
        return;
    }
 
    int m = (s + e) / 2;
    getTree(node * 2, s, m, i, j, k);
    getTree(node * 2 + 1, m + 1, e, i, j, k);
}
 
int main()
{
    ios_base::sync_with_stdio(false);
    cin.tie(NULL);
    cout.tie(NULL);
 
    cin >> N;
 
    for (int i = 1; i <= N; i++) {
        cin >> arr[i];
    }
 
    makeTree(11, N);
 
    cin >> M;
 
    while (M--) {
        int a, b, c;
        cin >> a >> b >> c;
 
        ans = 0;
 
        a ^= pre;
        b ^= pre;
        c ^= pre;
 
        getTree(11, N, a, b, c);
 
        cout << ans << '\n';
 
        pre = ans;
    }
}
cs
반응형
반응형

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

 

17022번: Sleepy Cow Sorting

The first line of input contains $N$. The second line contains $N$ space-separated integers: $p_1, p_2, p_3, \dots, p_N$, indicating the starting order of the cows.

www.acmicpc.net

 

 

[ 문제풀이 ]

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

https://rudalsd.tistory.com/364

 

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

1. 비재귀 세그먼트 트리 (Segment Tree) 재귀 세그먼트 트리에서는 항상 루트노드부터 시작했었습니다. 하지만 비재귀 세그먼트 트리에서는 반대로 리프노드부터 시작합니다. 2. 비재귀 세그먼트

rudalsd.tistory.com

 

1. N - 1부터 1까지 for문을 통해 돌면서 arr[ i ] < arr[ i - 1 ] 일 때의 i를 pivot으로 설정합니다.

 

2. pivot 부터 N - 1까지는 오름차순으로 정렬되어 있으므로 0부터 pivot - 1 까지의 수만 옮겨주면 됩니다.

 

3. 0부터 pivot - 1까지 for문을 통해 돌면서 pivot ~ N 까지의 수 중 현재 수보다 작은 수들의 개수와 현재 수 ~ pivot 사이의 수들의 개수를 더하면 원하는 수를 얻을 수 있습니다.

 

4. pivot을 출력하고, 앞의 수들의 이동 횟수를 출력합니다.

 

[ 소스코드 ]

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
#include<iostream>
 
using namespace std;
 
int N;
int arr[100000];
int segTree[200002];
int pivot;
 
void updateTree(int idx)
{
    while (idx != 0) {
        segTree[idx]++;
        idx >>= 1;
    }
}
 
int getTree(int l, int r)
{
    int ret = 0;
 
    while (l <= r) {
        if (l & 1) {
            ret += segTree[l];
            l++;
        }
        if (~r & 1) {
            ret += segTree[r];
            r--;
        }
        l >>= 1;
        r >>= 1;
    }
 
    return ret;
}
 
int main()
{
    scanf("%d"&N);
 
    for (int i = 0; i < N; i++) {
        scanf("%d"&arr[i]);
    }
 
    for (int i = N - 1; i > 0; i--) {
        if (arr[i] < arr[i - 1]) {
            pivot = i;
            break;
        }
    }
 
    for (int i = pivot; i < N; i++) {
        updateTree(N + arr[i] - 1);
    }
 
    printf("%d\n", pivot);
    for (int i = 0; i < pivot; i++) {
        printf("%d ", pivot - i - 1 + getTree(N, N + arr[i] - 1));
        updateTree(N + arr[i] - 1);
    }
}
cs
반응형
반응형

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

 

2820번: 자동차 공장

상근이는 자동차를 매우 좋아한다. 자동차 공장에 취직한 상근이는 계속된 승진 끝에 드디어 사장이 되었다. 공장에는 총 N명의 직원이 있다. 상근이를 제외한 모든 직원은 한 명의 상사가 있다.

www.acmicpc.net

 

 

[ 문제풀이 ]

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

https://rudalsd.tistory.com/256

 

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

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

rudalsd.tistory.com

 

1. 초기 월급을 arr배열에 저장하고, 그래프를 list에 저장합니다.

 

2. dfs를 통해 각 노드가 몇 번에서 시작해서 몇 번에서 끝나는지 오일러 경로 테크닉을 이용하여 st[ n ], en[ n ]에 저장하고, arr2[ st[ n ] ] = arr[ n ] 을 통해 초기화해 줍니다.

 

3. 초기 segmentTree를 만들 때 arr2를 기준으로 만듭니다.

 

4. 월급이 오르거나 내리면 느리게 갱신되는 세그먼트 트리를 이용하여 st[ i ] + 1부터 en[ i ]까지 월급을 더해줍니다.

 

5. segTree에서 해당 노드를 출력해 줍니다.

 

[ 소스코드 ]

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
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
#include<iostream>
#include<vector>
 
using namespace std;
 
int N, M;
unsigned int segTree[1050000];
unsigned int lazy[1050000];
vector<int> list[500001];
int st[500001];
int en[500001];
int arr[500001];
int arr2[500001];
int cnt;
 
void dfs(int num)
{
    st[num] = ++cnt;
    arr2[cnt] = arr[num];
 
    for (int& next : list[num]) {
        dfs(next);
    }
 
    en[num] = cnt;
}
 
void makeTree(int node, int s, int e)
{
    if (s == e) {
        segTree[node] = arr2[s];
        return;
    }
 
    int m = (s + e) / 2;
    makeTree(node * 2, s, m);
    makeTree(node * 2 + 1, m + 1, e);
}
 
void updateLazy(int node, int s, int e)
{
    if (lazy[node] != 0) {
        segTree[node] += lazy[node];
 
        if (s != e) {
            lazy[node * 2+= lazy[node];
            lazy[node * 2 + 1+= lazy[node];
        }
 
        lazy[node] = 0;
    }
}
 
void updateTree(int node, int s, int e, int sidx, int eidx, unsigned int diff)
{
    updateLazy(node, s, e);
 
    if (e < sidx || s > eidx) return;
    if (sidx <= s && e <= eidx) {
        if (s == e) {
            segTree[node] += diff;
        }
        else {
            lazy[node * 2+= diff;
            lazy[node * 2 + 1+= diff;
        }
        return;
    }
 
    int m = (s + e) / 2;
    updateTree(node * 2, s, m, sidx, eidx, diff);
    updateTree(node * 2 + 1, m + 1, e, sidx, eidx, diff);
}
 
void getTree(int node, int s, int e, int idx)
{
    updateLazy(node, s, e);
 
    if (idx < s || idx > e) return;
    if (s == e) {
        cout << segTree[node] << '\n';
        return;
    }
 
    int m = (s + e) / 2;
    getTree(node * 2, s, m, idx);
    getTree(node * 2 + 1, m + 1, e, idx);
}
 
int main()
{
    ios_base::sync_with_stdio(false);
    cin.tie(NULL);
    cout.tie(NULL);
 
    cin >> N >> M;
 
    for (int i = 1; i <= N; i++) {
        cin >> arr[i];
        if (i != 1) {
            int p;
            cin >> p;
            list[p].push_back(i);
        }
    }
 
    dfs(1);
 
    makeTree(11, N);
 
    for (int i = 0; i < M; i++) {
        char com;
        int a;
        cin >> com >> a;
 
        if (com == 'p') {
            unsigned int x;
            cin >> x;
 
            updateTree(11, N, st[a] + 1, en[a], x);
        }
        else {
            getTree(11, N, st[a]);
        }
    }
}
cs
반응형
반응형

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

 

1321번: 군인

첫째 줄에 부대의 개수 N(1 ≤ N ≤ 500,000)이 주어지고, 이어서 각 부대의 군사 수를 나타내는 정수가 N개 주어진다. 각 부대의 군사 수는 1000보다 작거나 같은 자연수이다. 그 다음 줄에 명령의 개

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
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
#include<iostream>
#include<cmath>
 
using namespace std;
 
int N, M;
int segTree[1111111];
int arr[500001];
 
void makeTree(int node, int s, int e)
{
    if (s == e) {
        segTree[node] = arr[s];
        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 idx, int a)
{
    if (idx < s || e < idx) return;
    segTree[node] += a;
 
    if (s != e) {
        int m = (s + e) / 2;
        updateTree(node * 2, s, m, idx, a);
        updateTree(node * 2 + 1, m + 1, e, idx, a);
    }
}
 
void getTree(int node, int s, int e, int idx)
{
    if (s == e) {
        printf("%d\n", s);
        return;
    }
 
    int m = (s + e) / 2;
    int left = segTree[node * 2];
    
    if (left >= idx) {
        getTree(node * 2, s, m, idx);
    }
    else {
        getTree(node * 2 + 1, m + 1, e, idx - left);
    }
 
    return;
}
 
int main()
{
    scanf("%d"&N);
 
    for (int i = 1; i <= N; i++) {
        scanf("%d"&arr[i]);
    }
 
    makeTree(11, N);
 
    scanf("%d"&M);
 
    for (int i = 0; i < M; i++) {
        int com, idx;
        scanf("%d %d"&com, &idx);
        if (com == 1) {
            int a;
            scanf("%d"&a);
            arr[idx] += a;
            updateTree(11, N, idx, a);
        }
        else {
            getTree(11, N, idx);
        }
    }
}
cs
반응형
반응형

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

 

7578번: 공장

어떤 공장에는 2N개의 기계가 2열에 걸쳐 N개씩 배치되어 있다. 이 2개의 열을 각각 A열과 B 열이라고 부른다. A열에 있는 N개의 기계는 각각이 B열에 있는 N개의 기계와 하나씩 짝을 이루어 케이블

www.acmicpc.net

 

 

[ 문제풀이 ]

 

이 문제를 풀기 전에 다음 글을 먼저 읽어보시는 것을 추천드립니다!

https://rudalsd.tistory.com/51?category=1073064 

 

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

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

rudalsd.tistory.com

 

1. A라인의 값들을 입력받을 때 각 숫자들의 인덱스를 저장해줍니다.

 

2. B라인의 값들을 입력 받을 때 이미 입력된 값들 중 현재 인덱스보다 더 높은 인덱스에 있는 값들의 개수를 ans에 더해줍니다.

 

3. 세그먼트 트리를 업데이트해줍니다.

 

[ 소스 코드 ]

 

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<cmath>
 
#define ll long long
 
using namespace std;
 
int N;
int A[1000001];
ll segTree[1111111];
 
ll getSum(int node, int start, int endint sidx, int eidx)        //현재 idx값보다 큰 값들의 수를 return
{
    if (sidx > end || eidx < start) return 0;
    if (sidx <= start && end <= eidx) return segTree[node];
 
    int mid = (start + end/ 2;
    ll left = getSum(node * 2, start, mid, sidx, eidx);
    ll right = getSum(node * 2 + 1, mid + 1end, sidx, eidx);
 
    return left + right;
}
 
ll update(int node, int start, int endint idx)        //현재 idx를 추가
{
    if (idx < start || idx > endreturn segTree[node];
    segTree[node]++;
    if (start == endreturn segTree[node];
 
    int mid = (start + end/ 2;
    ll left = update(node * 2, start, mid, idx);
    ll right = update(node * 2 + 1, mid + 1end, idx);
 
    return segTree[node] = left + right;
}
 
int main()
{
    scanf("%d"&N);
 
    ll ans = 0;
 
    for (int i = 1; i <= N; i++) {
        int num;
        scanf("%d"&num);
        A[num] = i;
    }
 
    for (int i = 1; i <= N; i++) {
        int num;
        scanf("%d"&num);
        int idx = A[num];
        ans += getSum(11, N, idx + 1, N);    //현재 idx보다 큰 값들의 수를 ans에 더하기
        update(11, N, idx);    //현재 idx값을 넣어주기
    }
 
    printf("%lld", ans);
}
cs
반응형

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

[ 백준 ] 14942번 - 개미 (C++)  (0) 2022.08.09
[ 백준 ] 13141번 - Ignition (C++)  (0) 2022.08.08
[ 백준 ] 16287번 - Parcel (C++)  (0) 2022.08.06
[ 백준 ] 10026번 - 적록색약 (C++)  (0) 2022.08.05
[ 백준 ] 11438번 - LCA 2 (C++)  (0) 2022.08.04
반응형

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

 

2243번: 사탕상자

첫째 줄에 수정이가 사탕상자에 손을 댄 횟수 n(1 ≤ n ≤ 100,000)이 주어진다. 다음 n개의 줄에는 두 정수 A, B, 혹은 세 정수 A, B, C가 주어진다. A가 1인 경우는 사탕상자에서 사탕을 꺼내는 경우이

www.acmicpc.net

 

 

[ 문제풀이 ]

 

이 문제를 풀기 전에 다음 글을 먼저 읽어보시는 것을 추천드립니다!!

 

https://rudalsd.tistory.com/51?category=1073064 

 

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

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

rudalsd.tistory.com

 

각각의 노드들에는 왼쪽 자식 노드 값 + 오른쪽 자식 노드 값을 넣어줍니다. 노드의 값은 가지고 있는 사탕의 개수이고, 이를 활용해서 특정 idx에 무슨 맛의 사탕이 있는지 알아낼 수 있습니다.

 

오른쪽 노드로 내려갈 때는 오른쪽 노드의 사탕 개수만 가지고 때문에 왼쪽 노드의 사탕 개수는 포함되어 있지 않습니다.

 

따라서, 오른쪽 노드로 내려갈 때는 idx에서 왼쪽 노드의 값을 빼주는 방법을 이용하여 문제를 풀 수 있습니다.

 

[ 소스 코드 ]

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
#include<iostream>
 
using namespace std;
 
int n;
int segTree[2111111];
 
void update(int node, int start, int endint taste, int N)    //사탕 숫자 update
{
    if (taste > end || taste < start) return;    //범위를 벗어나면
 
    segTree[node] += N;
 
    if (start == endreturn;    //범위에 완전히 포함되면
 
    //범위에 일부 포함되면
    int mid = (start + end/ 2;
    update(node * 2, start, mid, taste, N);
    update(node * 2 + 1, mid + 1end, taste, N);
}
 
int get(int node, int start, int endint idx)    //idx번째 사탕의 맛 얻기
{
    if (start == end) {        //범위에 정확히 들어오면
        return start;
    }
 
    int mid = (start + end/ 2;
    if (segTree[node * 2>= idx) return get(node * 2, start, mid, idx);    //왼쪽 자식 노드
    return get(node * 2 + 1, mid + 1end, idx - segTree[node * 2]);        //오른쪽 자식 노드
}
 
int main()
{
    scanf("%d"&n);
 
    for (int i = 0; i < n; i++) {
        int A, B, C;
        scanf("%d"&A);
 
        if (A == 1) {        //사탕 꺼내기
            scanf("%d"&B);
            int idx = get(111000000, B);
            printf("%d\n", idx);
            update(111000000, idx, -1);
        }
        else {                //사탕 넣고, 빼기
            scanf("%d %d"&B, &C);
            update(111000000, B, C);
        }
    }
}
cs
반응형

+ Recent posts