962. 最大宽度坡(权值线段树, 权值树状数组)
本题要快速找到某个数字在数组中左边<=它的数的最小下标。
可以建立一个权值线段树,nums[i]处维护最小下标。
class Solution { public: const static int N = 50010, INF = 0x3f3f3f3f; struct Node { int l, r, v; } tr[N * 4]; void pushup(int u) { tr[u].v = min(tr[u << 1].v, tr[u << 1 | 1].v); } void build(int u, int l, int r) { tr[u] = {l, r, INF}; if(l == r) return; int mid = l + r >> 1; build(u << 1, l, mid); build(u << 1 | 1, mid + 1, r); pushup(u); } void update(int u, int x, int v) { if(tr[u].l == tr[u].r) { tr[u].v = min(tr[u].v, v); return; } int mid = tr[u].l + tr[u].r >> 1; if(x <= mid) update(u << 1, x, v); else update(u << 1 | 1, x, v); pushup(u); } int query(int u, int l, int r) { if(tr[u].l >= l && tr[u].r <= r) { return tr[u].v; } int res = INF; int mid = tr[u].l + tr[u].r >> 1; if(l <= mid) res = min(res, query(u << 1, l, r)); if(r > mid) res = min(res, query(u << 1 | 1, l, r)); return res; } int maxWidthRamp(vector<int>& nums) { int mx = *max_element(nums.begin(), nums.end()), n = nums.size(); build(1, 0, mx); int ans = 0; for(int i = 0; i < n; i ++ ) { int p = query(1, 0, nums[i]); if(p < i) ans = max(ans, i - p); update(1, nums[i], i); } return ans; } };
权值树状数组
class Solution: def maxWidthRamp(self, nums: List[int]) -> int: n, ans = len(nums), 0 tree = [0x3f3f3f3f] * (int(5e4)+5) def update(u: int, v: int) -> None: while u < len(tree): tree[u] = min(tree[u], v) u += u & -u def query(u: int) -> int: res = tree[u] while u: res = min(res, tree[u]) u -= u & -u return res for i, e in enumerate(nums): ans = max(ans, i - query(e + 1)) update(e + 1, i) return ans