문제
- 문제 링크
BOJ 13519 - 트리와 쿼리 10
금광 세그를 선형 구조가 아닌 트리 위에서 한다면?
TL : $2$ sec, ML : $512$ MB
$2 ≤ N ≤ 100,000$ $1 ≤ Q ≤ 100,000$ $w_i ≤ |10,000|$
알고리즘 분류
- 자료 구조(data structures)
- 트리(trees)
- heavy-light 분할(heavy-light decomposition)
- 세그먼트 트리(segment tree)
- 느리게 갱신되는 세그먼트 트리(lazy propagation)
풀이
여기 서 다룬 문제에서 이미 대차게 얻어 맞았었기 때문에 ,
사실상 복기하는 느낌으로 코드를 작성했다.
풀이는 저기서 다룬 내용과 99% 동일하니 간략하게 차이점만 짚고 넘어 가겠다.
그나마 차이점이라곤 $N$ 및 $Q$의 범위이며, 정답은 $0$보다 크거나 같다는 것이다.
이에 따라 레이지 값을 뿌려줄 때
$seg[n].ls = seg[n].rs = seg[n].ms =$ $max(lz[n], seg[n].ps)$ 가 아닌
$seg[n].ls = seg[n].rs = seg[n].ms =$ $max(0LL, seg[n].ps)$ 의 값을 취해 주는 것이 핵심이다.
위에서 언급한 문제가 답의 범위 제한이 없음에 따라, 좀 더 일반적인 형태인 듯 하다.
전체 코드
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 | #include<bits/stdc++.h> #define r ll n, ll s, ll e #define ll long long #define N 100001 using namespace std; struct T { ll ls, rs, ps, ms; }seg[1 << 18]; vector <int> Gr[N], G[N]; int top[N], in[N], lz[1 << 18]; int P[N], D[N], S[N], C[N]; ll n, q, i, j, M(-1e9); T f(T x, T y) { return { max(x.ls, x.ps + y.ls), max(y.rs, y.ps + x.rs), x.ps + y.ps, max({x.ms, y.ms, x.rs + y.ls}) }; } void f0() // input { ios_base::sync_with_stdio(0); cin.tie(0); fill(lz, lz + (1 << 18), M); seg[n] = { M, M, 0, M }; for (cin >> n; ++i <= n; cin >> C[i]); for (int o{}; o++ < n - 1;) cin >> i >> j, Gr[i].push_back(j), Gr[j].push_back(i); } void f1(int p) // hld_init_dfs { S[p] = 1; for (int& i : Gr[p]) if (!S[i]) { D[i] = D[p] + 1; P[i] = p; f1(i); S[p] += S[i]; G[p].push_back(i); if (S[i] > S[G[p][0]]) swap(G[p][0], G[p].back()); } } void f2(int p) // hld_init_dfs2 { in[p] = ++q; for (int& i : G[p]) top[i] = i == G[p][0] ? top[p] : i, f2(i); } void f3(r) // lazy_update { if (lz[n] == M) return; if (s ^ e) lz[n << 1] = lz[n << 1 | 1] = lz[n]; seg[n].ps = lz[n] * (e - s + 1); seg[n].ls = seg[n].rs = seg[n].ms = max(0LL, seg[n].ps); lz[n] = M; } T f4(r, ll p, ll q, ll k) // seg_update { f3(n, s, e); if (s > q || e < p) return seg[n]; if (s >= p && e <= q) return (lz[n] = k, f3(n, s, e)), seg[n]; T L(f4(n << 1, s, (s + e) >> 1, p, q, k)), R(f4(n << 1 | 1, ((s + e) >> 1) + 1, e, p, q, k)); return seg[n] = f(L, R); } T f5(r, ll p, ll q) // seg_query { f3(n, s, e); if (s > q || e < p) return seg[0]; if (s >= p && e <= q) return seg[n]; T L(f5(n << 1, s, (s + e) >> 1, p, q)), R(f5(n << 1 | 1, ((s + e) >> 1) + 1, e, p, q)); return f(L, R); } void f6(ll x, ll y, ll w) // hld_update_query { while (top[x] ^ top[y]) { if (D[top[x]] < D[top[y]]) swap(x, y); f4(1, 1, n, in[top[x]], in[x], w); x = P[top[x]]; } if (D[x] > D[y]) swap(x, y); f4(1, 1, n, in[x], in[y], w); } ll f7(ll x, ll y) // hld_get_query { T p(seg[0]), q(seg[0]); while (top[x] ^ top[y]) D[top[x]] > D[top[y]] ? p = f(f5(1, 1, n, in[top[x]], in[x]), p), x = P[top[x]] : (q = f(f5(1, 1, n, in[top[y]], in[y]), q), y = P[top[y]]); if (D[x] > D[y]) swap(x, y), swap(p, q); swap(p.ls, p.rs); return f(p, f(f5(1, 1, n, in[x], in[y]), q)).ms; } void sv() { for (cin >> q, i = 1; i <= n; i++) f6(i, i, C[i]); for (ll o, w; q--;) if (cin >> o >> i >> j; o & 1) cout << f7(i, j) << '\n'; else cin >> w, f6(i, j, w); } int main() { f0(); f1(1); f2(1); sv(); } | cs |
comment
끝
'Problem Solving > Baekjoon Online Judge (Diamond)' 카테고리의 다른 글
백준 25078 - Software Package Manager (C++) (0) | 2023.04.30 |
---|---|
백준 17429 - 국제 메시 기구 (C++) (0) | 2023.04.29 |
백준 17526 - Star Trek (C++) (0) | 2023.04.27 |
백준 6171 - 땅따먹기 (C++) (0) | 2023.04.27 |
백준 15249 - Building Bridges (C++) (0) | 2023.04.26 |