728x90
728x90

문제 링크 : https://www.acmicpc.net/problem/2042

 

2042번: 구간 합 구하기

첫째 줄에 수의 개수 N(1 ≤ N ≤ 1,000,000)과 M(1 ≤ M ≤ 10,000), K(1 ≤ K ≤ 10,000) 가 주어진다. M은 수의 변경이 일어나는 횟수이고, K는 구간의 합을 구하는 횟수이다. 그리고 둘째 줄부터 N+1번째 줄

www.acmicpc.net

 

 

문제

어떤 N개의 수가 주어져 있다. 그런데 중간에 수의 변경이 빈번히 일어나고 그 중간에 어떤 부분의 합을 구하려 한다. 만약에 1,2,3,4,5 라는 수가 있고, 3번째 수를 6으로 바꾸고 2번째부터 5번째까지 합을 구하라고 한다면 17을 출력하면 되는 것이다. 그리고 그 상태에서 다섯 번째 수를 2로 바꾸고 3번째부터 5번째까지 합을 구하라고 한다면 12가 될 것이다.

입력

첫째 줄에 수의 개수 N(1 ≤ N ≤ 1,000,000)과 M(1 ≤ M ≤ 10,000), K(1 ≤ K ≤ 10,000) 가 주어진다. M은 수의 변경이 일어나는 횟수이고, K는 구간의 합을 구하는 횟수이다. 그리고 둘째 줄부터 N+1번째 줄까지 N개의 수가 주어진다. 그리고 N+2번째 줄부터 N+M+K+1번째 줄까지 세 개의 정수 a, b, c가 주어지는데, a가 1인 경우 b(1 ≤ b ≤ N)번째 수를 c로 바꾸고 a가 2인 경우에는 b(1 ≤ b ≤ N)번째 수부터 c(b ≤ c ≤ N)번째 수까지의 합을 구하여 출력하면 된다.

입력으로 주어지는 모든 수는 -2^63보다 크거나 같고, 2^63-1보다 작거나 같은 정수이다.

출력

첫째 줄부터 K줄에 걸쳐 구한 구간의 합을 출력한다. 단, 정답은 -263보다 크거나 같고, 263-1보다 작거나 같은 정수이다.

 

 


접근 방법

데이터가 최근에 추가된 것 같은데, 문제에 주어진 조건이 명확하지 않아서 정답까지 오래 걸린 문제였다. N의 최대 값은 int 형인데 b,c모두 N을 넘지 않으므로 int형으로 선언했는데 계속 틀렸습니다가 출력됐다. 

100%에서 틀리는 경우에는 a,b,c모두 long long 으로 선언해서 다시 시도해보도록 하자! (c만 long long 으로 선언해줘도 되는데 문제에서 입력값 모두 long long형이라고 했으므로, 입력 값은 맘 편하게 모두 long long으로 선언하도록 하자.)

 

참고 : https://www.acmicpc.net/board/view/62196

 

글 읽기 - 데이터를 추가해주세요.

댓글을 작성하려면 로그인해야 합니다.

www.acmicpc.net

 

 

#define MAX 1000001
#include <iostream>
using namespace std;

int N, M, K;
long long arr[MAX];

long long segTree[4000004];

long long init(int start, int end, int nodeNum)
{ //start : 시작 인덱스, end : 끝 인덱스,
    if (start == end)
        return segTree[nodeNum] = arr[start]; //리프 노드

    int mid = (start + end) / 2;
    return segTree[nodeNum] = init(start, mid, nodeNum * 2) + init(mid + 1, end, nodeNum * 2 + 1);
}

//start, end : 해당 노드의 시작, 끝 인덱스
//left, right : 구간 합 구하고자 하는 범위
long long subSum(int start, int end, int nodeNum, int left, int right)
{
    if (left > end || right < start)
        return 0;

    if (left <= start && end <= right)
        return segTree[nodeNum]; //완전히 포함 (6~11 구하고 싶은데 해당 노드가 6~8일 때)
    int mid = (start + end) / 2;
    return subSum(start, mid, nodeNum * 2, left, right) + subSum(mid + 1, end, nodeNum * 2 + 1, left, right);
}

void update(int start, int end, int nodeNum, int targetIdx, long long val)
{
    if (targetIdx < start || end < targetIdx)
        return;

    segTree[nodeNum] += val;
    if (start == end)
        return;
    int mid = (start + end) / 2;
    update(start, mid, nodeNum * 2, targetIdx, val);
    update(mid + 1, end, nodeNum * 2 + 1, targetIdx, val);
}

int main()
{

    cin >> N >> M >> K;

    int num;
    for (int i = 0; i < N; i++)
    {
        cin >> arr[i];
    }

    //1. 세그먼트트리 만들기 (트리 인덱스는 1부터 ~ )
    init(0, N - 1, 1);

    long long a, b, c;
    for (int i = 0; i < M + K; i++)
    {
        cin >> a >> b >> c;
        if (a == 1)
        { //b번째 인덱스를 c로 바꾸기. 바뀐 차이 만큼 트리 각 노드에 더해줘야함.
            long long tmp = c - arr[b - 1];	//arr 값 바꾸기 전에 값 저장해놓아야 파라미터로 넘길 수 있음
            arr[b - 1] = c;
            update(0, N - 1, 1, b - 1, tmp);
        }
        else
        { //b~c 합(b=3, c = 7이면 arr[2]~arr[6] 구해야 함)
            cout << subSum(0, N - 1, 1, b - 1, c - 1) << "\n";
        }
    }

    return 0;
}

728x90

'Algorithm(BOJ) > Tree' 카테고리의 다른 글

[C++] 백준 1991번 - 트리 순회 (unordered_map)  (0) 2021.07.01
728x90

문제 링크 : https://www.acmicpc.net/problem/1991

 

1991번: 트리 순회

첫째 줄에는 이진 트리의 노드의 개수 N(1≤N≤26)이 주어진다. 둘째 줄부터 N개의 줄에 걸쳐 각 노드와 그의 왼쪽 자식 노드, 오른쪽 자식 노드가 주어진다. 노드의 이름은 A부터 차례대로 영문자

www.acmicpc.net

 

문제

이진 트리를 입력받아 전위 순회(preorder traversal), 중위 순회(inorder traversal), 후위 순회(postorder traversal)한 결과를 출력하는 프로그램을 작성하시오.

예를 들어 위와 같은 이진 트리가 입력되면,

  • 전위 순회한 결과 : ABDCEFG // (루트) (왼쪽 자식) (오른쪽 자식)
  • 중위 순회한 결과 : DBAECFG // (왼쪽 자식) (루트) (오른쪽 자식)
  • 후위 순회한 결과 : DBEGFCA // (왼쪽 자식) (오른쪽 자식) (루트)

가 된다.

입력

첫째 줄에는 이진 트리의 노드의 개수 N(1≤N≤26)이 주어진다. 둘째 줄부터 N개의 줄에 걸쳐 각 노드와 그의 왼쪽 자식 노드, 오른쪽 자식 노드가 주어진다. 노드의 이름은 A부터 차례대로 영문자 대문자로 매겨지며, 항상 A가 루트 노드가 된다. 자식 노드가 없는 경우에는 .으로 표현된다.

출력

첫째 줄에 전위 순회, 둘째 줄에 중위 순회, 셋째 줄에 후위 순회한 결과를 출력한다. 각 줄에 N개의 알파벳을 공백 없이 출력하면 된다.

 

 


 

접근 방법

value를 pair로 지정해서 각각 first 는 leftChild로, second는 rightChild를 설정해준다.

그 후 전위, 중위, 후위 탐색 알고리즘에 맞게 unordered_map의 key와 value를 이용해준다. 

 

//
//  Tree_BOJ19991_트리순회.cpp
//  Coding_Test_Practice
//
//  Created by 김난영 on 2021/07/01.
//  Copyright © 2021 KimNanyoung. All rights reserved.
//

#include <iostream>
#include <unordered_map>
#include <utility>
using namespace std;

int N;
unordered_map<char, pair<char,char>> umap;

void preOrder(char c){
    if(umap.find(c) == umap.end()) return;
    else{
        cout << c;
        if(umap.find(umap[c].first) != umap.end() && umap[c].first != '.') preOrder(umap[c].first);
        if(umap.find(umap[c].second) != umap.end() && umap[c].second != '.') preOrder(umap[c].second);
    }
    
}
void inOrder(char c){
    if(umap.find(c) == umap.end()) return;
    else{
        if(umap.find(umap[c].first) != umap.end() && umap[c].first != '.') inOrder(umap[c].first);
        if(umap.find(umap[c].second) != umap.end() && umap[c].second != '.') inOrder(umap[c].second);
        cout << c;

    }
    
}
void postOrder(char c){
    if(umap.find(c) == umap.end()) return;
    else{
        if(umap.find(umap[c].first) != umap.end() && umap[c].first != '.') postOrder(umap[c].first);
        if(umap.find(umap[c].second) != umap.end() && umap[c].second != '.') postOrder(umap[c].second);
        cout << c;

    }
    
}

int main(){
    cin.tie(NULL);
    ios_base::sync_with_stdio(false);
    cin >> N;

    for(int i = 0; i<N; i++){
        char p, n1, n2;
        cin >> p >> n1 >> n2;
        umap[p] = make_pair(n1, n2);
    }
    
    preOrder('A');
    cout << "\n";
    inOrder('A');
    cout << "\n";
    postOrder('A');

    
    return 0;
}

728x90

+ Recent posts