#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 best_ans(int a, int b, int goal) {
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[goal]) {
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[goal]) {
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 != goal) {
if (jump[curr][0] == -1 || h[jump[curr][0]] > h[goal]) break;
for (int j = LOG-1; j >= 0; j--) {
if (jump[curr][j] == -1) continue;
if (h[jump[curr][j]] <= h[goal]) {
tot += dp[curr][j];
curr = jump[curr][j];
break;
}
}
}
if (curr == goal) return tot;
// now only left, or only right
if (curr < goal) {
while (curr != goal) {
if (jumpR[curr][0] == -1 || h[jumpR[curr][0]] > h[goal]) return -1;
for (int j = LOG-1; j >= 0; j--) {
if (jumpR[curr][j] != -1 && h[jumpR[curr][j]] <= h[goal]) {
tot += dpR[curr][j];
curr = jumpR[curr][j];
break;
}
}
}
}
else {
while (curr != goal) {
if (jumpL[curr][0] == -1 || h[jumpL[curr][0]] > h[goal]) return -1;
for (int j = LOG-1; j >= 0; j--) {
if (jumpL[curr][j] != -1 && h[jumpL[curr][j]] <= h[goal]) {
tot += dpL[curr][j];
curr = jumpL[curr][j];
break;
}
}
}
}
return tot;
}
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]
a++;b++;c++;d++;
int maxV = segTree.query(roots.back(), c, d);
int ans1 = best_ans(a, b, maxV);
if (ans1 == -1) return -1;
int ans2 = -1;
if (b + 1 < c) ans2 = best_ans(a, b, segTree.query(roots.back(), b+1, c-1));
if (ans2 != -1) ans2++;
int ans3 = -1;
if (a > 1) {
int needBigger = 0;
if (b+1 < c) {
needBigger = segTree.query(roots.back(), b+1, c-1);
}
int finIdx = -1;
int lo = 1, hi = a-1;
while (lo <= hi) {
int mid = (lo + hi) / 2;
int idx = segTree.query(roots.back(), mid, a-1);
if (h[idx] > h[needBigger]) {
finIdx = idx;
lo = mid+1;
}
else hi = mid-1;
}
if (finIdx != -1 && h[finIdx] < h[maxV]) {
ans3 = best_ans(a, b, finIdx);
int lo = c, hi = d;
int fin2 = -1;
while (lo <= hi) {
int mid = (lo + hi) / 2;
int idx = segTree.query(roots.back(), c, mid);
if (h[idx] > h[finIdx]) {
fin2 = idx;
hi = mid-1;
}
else lo = mid+1;
}
int nxt = best_ans(finIdx, finIdx, fin2);
if (ans3 != -1 && nxt != -1) ans3 += nxt;
}
}
if (ans2 == -1) ans2 = INF;
if (ans3 == -1) ans3 = INF;
return min({ans1, ans2, ans3});
}
# | Verdict | Execution time | Memory | Grader output |
---|
Fetching results... |
# | Verdict | Execution time | Memory | Grader output |
---|
Fetching results... |
# | Verdict | Execution time | Memory | Grader output |
---|
Fetching results... |
# | Verdict | Execution time | Memory | Grader output |
---|
Fetching results... |
# | Verdict | Execution time | Memory | Grader output |
---|
Fetching results... |
# | Verdict | Execution time | Memory | Grader output |
---|
Fetching results... |
# | Verdict | Execution time | Memory | Grader output |
---|
Fetching results... |