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


아이디어

  • 상사와의 관계를 인접 행렬로 관리

    • 업데이트 할경우 인접행렬을 업데이트
    • 시간복잡도 : O(M * N) : 2.5e11 > 시간초과
  • 레이지 개념 사용할 수 있을까?

    • a의 부하의 월급을 증가할떄 : a에 임시로 달아놓음
    • u로 출력할때 : 상사에서부터 lazy 업데이트 후 출력
    • 시간복잡도 : 편향트리일때 O(MN) > 시간초과
  • 자식 관계를 세그먼트 트리에 입력

    • 트리가 편향되어있을때 O(NM)을 세그먼트에 넣어 O(NlgM)으로 만듬
    • 세그먼트에 넣도록 노드를 배열에 각각 넣음
    • l 배열 : 자기자신 인덱스, 다음값부터 자식 인덱스
    • r 배열 : 자식 마지막 인덱스
    • 업데이트 시 l+1 부터 r까지 업데이트

시간복잡도 계산

  • 세그먼트 트리 생성 : O(NlgN)
  • 출력 : O(MlgN)

인트 계산

  • 트리 : 항상 2^31-1 이하이지만 중간에 넘칠 수 있으므로 > ll 사용
  • lazy :중간에 넘칠수 있으므로 ll 사용

코드

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
#include <iostream>
#include <vector>
#include <cmath>
 
using namespace std;
typedef long long ll;
 
vector<ll> tree;
vector<ll> lazy;
 
int initSalary[500010];
int l[500010];
int r[500010];
int segToOrigin[500010];
vector<int> child[500010];
 
void dfs(int cur, int &idx) {
    l[cur] = ++idx;
    for(int x : child[cur]) dfs(x, idx);
    r[cur] = idx;
}
 
void make(int node, int st, int en) {
    if(st== en) {
        tree[node] = initSalary[segToOrigin[st]];
        return;
    }
    
    int mid = (st+en)/2;
    make(node*2, st, mid);
    make(node*2+1, mid+1, en);
}
 
void lazy_update(int node, int st, int en) {
    if(lazy[node] != 0) {
        if(st == en) tree[node] += lazy[node];
        else {
            lazy[node*2+= lazy[node];
            lazy[node*2+1+= lazy[node];
        }
        lazy[node] = 0;
    }
}
 
void update(int node, int st, int en, int li, int ri, int diff) {
    lazy_update(node, st, en);
    if(ri < st || en < li) return;
    if(li <= st && en <= ri) {
        if(st == en) tree[node] += diff;
        else {
            lazy[node*2+= diff;
            lazy[node*2+1+= diff;
        }
        return;
    }
    
    int mid = (st+en)/2;
    update(node*2, st, mid, li, ri, diff);
    update(node*2+1, mid+1, en, li, ri, diff);
}
 
ll query(int node, int st, int en, int idx) {
    lazy_update(node, st, en);
    if(st == en) return tree[node];
    
    int mid = (st+en)/2;
    if(idx <= mid) return query(node*2, st, mid, idx);
    else return query(node*2+1, mid+1, en, idx);
}
 
 
int main() {
    ios::sync_with_stdio(0);
    cin.tie(0);
    
    fill(initSalary, initSalary+5000100);
    fill(l, l+5000100);
    fill(r, r+5000100);
    fill(segToOrigin, segToOrigin+5000100);
    int N,M; cin >> N >> M;
    
    cin >> initSalary[1];
    
    for(int i=2; i<=N; i++) {
        int a,b; cin >> a >> b;
        initSalary[i] = a;
        child[b].push_back(i);
    }
    int idx = -1;
    // 세그먼트 위치 설정
    dfs(1, idx);
    
    // 세그먼트에서 원래로 가는 값
    for(int i=1; i<=N; i++) {
        segToOrigin[l[i]] = i;
    }
        
    int h = ceil(log2(N));
    tree.resize(1<<(h+1));
    lazy.resize(1<<(h+1));
    
    make(1,0,N-1);
    for(int i=0; i<M; i++) {
        char order; cin >> order;
        if(order == 'p') {
            int a,b; cin >> a >> b;
            // 자식이 없으면 건너뜀
            if(l[a] == r[a]) continue;
            update(1,0,N-1,l[a]+1, r[a], b);
        } else {
            int a; cin >> a;
            cout << query(1,0,N-1,l[a]) << '\n';
        }
    }
    
    return 0;
}
 
cs

문제유형

  • 세그먼트 - 부모 자식 문제
    • 트리가 편향되어있을때 O(NM)을 세그먼트에 넣어 O(NlgM)으로 만듬
    • 세그먼트에 넣도록 노드를 배열에 각각 넣음
    • l 배열 : 자기자신 인덱스, 다음값부터 자식 인덱스
    • r 배열 : 자식 마지막 인덱스
    • 업데이트 시 l+1 부터 r까지 업데이트

+ Recent posts