제출 #1223923

#제출 시각아이디문제언어결과실행 시간메모리
1223923SpyrosAliv밀림 점프 (APIO21_jumps)C++20
0 / 100
0 ms408 KiB
#include <bits/stdc++.h> using namespace std; const int INF = 1e9; const int LOG = 22; int n; vector<int> h; vector<int> toL, toR; vector<vector<int>> g, revG; vector<int> deg; vector<int> lead; vector<vector<int>> jump, dp, jumpR, jumpL, dpR, dpL; vector<int> roots; struct Node { int maxv = 0, idx = 0, ll = -1, rr = -1; }; class PersistentSeg { private: int n; vector<Node> seg; int t = 1; Node merge(Node a, Node b, int l, int r) { if (a.maxv >= b.maxv) { return {a.maxv, a.idx, l, r}; } else return {b.maxv, b.idx, l, r}; } int build(int l, int r) { if (l == r) { seg.push_back({0, l, l, r}); return t++; } else { int mid = (l + r) / 2; Node nxt = {0, l, build(l, mid), build(mid+1, r)}; seg.push_back(nxt); return t++; } } pair<int, int> query(Node node, int start, int end, int l, int r) { if (start > r || end < l) return {0, 0}; if (start >= l && end <= r) { return {node.idx, node.maxv}; } else { int mid = (start + end) / 2; pair<int, int> canda = query(seg[node.ll], start, mid, l, r), candb = query(seg[node.rr], mid+1, end, l, r); if (canda.second > candb.second) return canda; else return candb; } } int update(int node, int start, int end, int idx, int v) { if (start == end) { seg.push_back({v, idx, 0, 0}); return t++; } else { int mid = (start + end) / 2; Node nxt = seg[node]; if (mid >= idx) { nxt.ll = update(seg[node].ll, start, mid, idx, v); } else nxt.rr = update(seg[node].rr, mid+1, end, idx, v); nxt = merge(seg[nxt.ll], seg[nxt.rr], nxt.ll, nxt.rr); seg.push_back(nxt); return t++; } } public: int init(int nn) { n = nn; //Node uh; //seg.assign(n*LOG, uh); seg.push_back({0, 0, 0, 0}); t = 1; return build(1, n); } int query(int root, int l, int r) { return query(seg[root], 1, n, l, r).first; } int update(int root, int idx, int v) { return update(root, 1, n, idx, v); } } segTree; void init(int N, vector<int> H) { n = N; h = {0}; toL.assign(n+1, 0); toR.assign(n+1, 0); for (auto x: H) h.push_back(x); stack<int> st; for (int i = 1; i <= n; i++) { while (!st.empty() && h[st.top()] <= h[i]) st.pop(); if (st.empty()) toL[i] = 0; else toL[i] = st.top(); st.push(i); } while (!st.empty()) st.pop(); for (int i = n; i >= 1; i--) { while (!st.empty() && h[st.top()] <= h[i]) st.pop(); if (st.empty()) toR[i] = n+1; else toR[i] = st.top(); st.push(i); } lead.assign(n+1, -1); for (int i = 1; i <= n; i++) { if (toL[i] < 1 && toR[i] > n) { lead[i] = -1; } else { if (toR[i] > n) lead[i] = toL[i]; else if (toL[i] < 1) lead[i] = toR[i]; else { if (h[toL[i]] > h[toR[i]]) lead[i] = toL[i]; else lead[i] = toR[i]; } } } vector<pair<int, int>> vals; for (int i = 1; i <= n; i++) { vals.push_back({h[i], i}); } sort(vals.rbegin(), vals.rend()); jump.assign(n+1, vector<int>(LOG, -1)); dp.assign(n+1, vector<int>(LOG, 0)); for (auto [curr, pos]: vals) { jump[pos][0] = lead[pos]; dp[pos][0] = 1; for (int i = 1; i < LOG; i++) { if (jump[pos][i-1] == -1) { jump[pos][i] = -1; dp[pos][i] = -1; continue; } jump[pos][i] = jump[jump[pos][i-1]][i-1]; int prev = jump[pos][i-1]; dp[pos][i] = dp[pos][i-1] + dp[prev][i-1]; } } jumpL.assign(n+1, vector<int>(LOG, -1)); dpL.assign(n+1, vector<int>(LOG, 0)); jumpR.assign(n+1, vector<int>(LOG, -1)); dpR.assign(n+1, vector<int>(LOG, 0)); for (int i = n; i >= 1; i--) { if (toR[i] > n) continue; jumpR[i][0] = toR[i]; dpR[i][0] = 1; for (int j = 1; j < LOG; j++) { if (jumpR[i][j-1] == -1) { jumpR[i][j] = -1; dpR[i][j] = -1; continue; } jumpR[i][j] = jumpR[jumpR[i][j-1]][j-1]; int prevPos = jumpR[i][j-1]; dpR[i][j] = dpR[i][j-1] + dpR[prevPos][j-1]; } } for (int i = 1; i <= n; i++) { if (toL[i] < 1) continue; jumpL[i][0] = toL[i]; dpL[i][0] = 1; for (int j = 1; j < LOG; j++) { if (jumpL[i][j-1] == -1) { jumpL[i][j] = -1; dpL[i][j] = -1; continue; } jumpL[i][j] = jumpL[jumpL[i][j-1]][j-1]; int prevPos = jumpL[i][j-1]; dpL[i][j] = dpL[i][j-1] + dpL[prevPos][j-1]; } } roots.push_back(segTree.init(n)); reverse(vals.begin(), vals.end()); for (auto [v, idx]: vals) { roots.push_back(segTree.update(roots.back(), idx, v)); } } int minimum_jumps(int a, int b, int c, int d) { // start from max in [a, b] //either do normal solution (subs 5-6 and get to any in [c, d]) // or go from start -> max in range (a, c) with sol -> range [c, d] int maxV = segTree.query(roots.back(), c, d); a++;b++;c++;d++; int start = -1; int lo = a, hi = b; int allowed = -1; while (lo <= hi) { int mid = (lo + hi) / 2; int mx = segTree.query(roots.back(), mid, b); if (h[mx] < h[maxV]) { allowed = mid; hi = mid-1; } else lo = mid+1; } if (allowed == -1) return -1; a = allowed; lo = 1, hi = n; while (lo <= hi) { int mid = (lo + hi) / 2; int mx = segTree.query(roots[mid], a, b); if (mx == 0 || h[mx] < h[maxV]) { if (mx != 0) start = mx; lo = mid+1; } else hi = mid-1; } if (start == -1) return -1; a = start; int tot = 0; int curr = a; while (curr < c || curr > d) { if (jump[curr][0] == -1 || h[jump[curr][0]] > h[maxV]) break; for (int j = LOG-1; j >= 0; j--) { if (jump[curr][j] == -1) continue; if (h[jump[curr][j]] <= h[maxV]) { tot += dp[curr][j]; curr = jump[curr][j]; break; } } } if (curr == d) return tot; // now only left, or only right if (curr < d) { while (curr < c || curr > d) { if (jumpR[curr][0] == -1 || h[jumpR[curr][0]] > h[maxV]) return -1; for (int j = LOG-1; j >= 0; j--) { if (jumpR[curr][j] != -1 && h[jumpR[curr][j]] <= h[maxV]) { tot += dpR[curr][j]; curr = jumpR[curr][j]; break; } } } } else { while (curr < c || curr > d) { if (jumpL[curr][0] == -1 || h[jumpL[curr][0]] > h[d]) return -1; for (int j = LOG-1; j >= 0; j--) { if (jumpL[curr][j] != -1 && h[jumpL[curr][j]] <= h[d]) { tot += dpL[curr][j]; curr = jumpL[curr][j]; break; } } } } int ans1 = tot; if (c == b + 1) return tot; maxV = segTree.query(roots.back(), b+1, c-1); d = maxV; start = -1; lo = a, hi = b; allowed = -1; while (lo <= hi) { int mid = (lo + hi) / 2; int mx = segTree.query(roots.back(), mid, b); if (h[mx] < h[d]) { allowed = mid; hi = mid-1; } else lo = mid+1; } if (allowed == -1) return ans1; a = allowed; lo = 1, hi = n; while (lo <= hi) { int mid = (lo + hi) / 2; int mx = segTree.query(roots[mid], a, b); if (mx == 0 || h[mx] < h[d]) { if (mx != 0) start = mx; lo = mid+1; } else hi = mid-1; } if (start == -1) return ans1; a = start; tot = 1; curr = a; while (curr >= 1 && curr <= n && curr != d) { if (jump[curr][0] == -1 || h[jump[curr][0]] > h[d]) break; for (int j = LOG-1; j >= 0; j--) { if (jump[curr][j] == -1) continue; if (h[jump[curr][j]] <= h[d]) { tot += dp[curr][j]; curr = jump[curr][j]; break; } } } if (curr == d) return min(tot, ans1); // now only left, or only right if (curr < d) { while (curr != d) { if (jumpR[curr][0] == -1 || h[jumpR[curr][0]] > h[d]) return ans1; for (int j = LOG-1; j >= 0; j--) { if (jumpR[curr][j] != -1 && h[jumpR[curr][j]] <= h[d]) { tot += dpR[curr][j]; curr = jumpR[curr][j]; break; } } } } else { while (curr != d) { if (jumpL[curr][0] == -1 || h[jumpL[curr][0]] > h[d]) return ans1; for (int j = LOG-1; j >= 0; j--) { if (jumpL[curr][j] != -1 && h[jumpL[curr][j]] <= h[d]) { tot += dpL[curr][j]; curr = jumpL[curr][j]; break; } } } } return min(ans1, tot); }
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...