Problem

A peak in an array arr is an element that is greater than its previous and next element in arr.

You are given an integer array nums and a 2D integer array queries.

You have to process queries of two types:

  • queries[i] = [1, li, ri], determine the count of peak elements in the subarray nums[li..ri].
  • queries[i] = [2, indexi, vali], change nums[indexi] to vali.

Return an array answer containing the results of the queries of the first type in order.

Notes:

  • The first and the last element of an array or a subarray cannot be a peak.

Examples

Example 1

 1
 2
 3
 4
 5
 6
 7
 8
 9
10

Input: nums = [3,1,4,2,5], queries = [[2,3,4],[1,0,4]]

Output: [0]

Explanation:

First query: We change `nums[3]` to 4 and `nums` becomes `[3,1,4,4,5]`.

Second query: The number of peaks in the `[3,1,4,4,5]` is 0.

Example 2

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12

Input: nums = [4,1,4,2,1,5], queries = [[2,2,4],[1,0,2],[1,0,4]]

Output: [0,1]

Explanation:

First query: `nums[2]` should become 4, but it is already set to 4.

Second query: The number of peaks in the `[4,1,4]` is 0.

Third query: The second 4 is a peak in the `[4,1,4,2,1]`.

Constraints

  • 3 <= nums.length <= 10^5
  • 1 <= nums[i] <= 10^5
  • 1 <= queries.length <= 10^5
  • queries[i][0] == 1 or queries[i][0] == 2
  • For all i that:
  • queries[i][0] == 1: 0 <= queries[i][1] <= queries[i][2] <= nums.length - 1
  • queries[i][0] == 2: 0 <= queries[i][1] <= nums.length - 1, 1 <= queries[i][2] <= 10^5

Solution

Intuition

We need to efficiently support range peak queries and point updates. A peak is an element greater than its neighbors, and only elements at positions 1..n-2 can be peaks. We can use a Binary Indexed Tree (Fenwick Tree) or Segment Tree to maintain a binary array where 1 means the position is a peak, and 0 otherwise. For updates, only the updated index and its neighbors can change peak status.

Approach

  1. Precompute a binary array is_peak where is_peak[i] = 1 if nums[i] is a peak.
  2. Build a Fenwick Tree (or Segment Tree) over is_peak for range sum queries.
  3. For update queries, update nums[index] and recompute peak status for index-1, index, and index+1.
  4. For range queries, query the sum of is_peak in [li+1, ri-1] (since endpoints can’t be peaks).

Code

C++
 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
#include <vector>
using namespace std;
class Fenwick {
    vector<int> bit; int n;
public:
    Fenwick(int n): bit(n+2), n(n+2) {}
    void add(int i, int x) { for (++i; i < n; i += i&-i) bit[i] += x; }
    int sum(int i) { int s = 0; for (++i; i > 0; i -= i&-i) s += bit[i]; return s; }
    int range(int l, int r) { return sum(r) - sum(l-1); }
};
class Solution {
public:
    vector<int> processQueries(vector<int>& nums, vector<vector<int>>& queries) {
        int n = nums.size();
        vector<int> is_peak(n, 0);
        auto check = [&](int i) {
            return i > 0 && i < n-1 && nums[i] > nums[i-1] && nums[i] > nums[i+1];
        };
        for (int i = 1; i < n-1; ++i) is_peak[i] = check(i);
        Fenwick bit(n);
        for (int i = 0; i < n; ++i) if (is_peak[i]) bit.add(i, 1);
        vector<int> res;
        for (auto& q : queries) {
            if (q[0] == 1) {
                int l = q[1], r = q[2];
                if (r - l < 2) res.push_back(0);
                else res.push_back(bit.range(l+1, r-1));
            } else {
                int idx = q[1], val = q[2];
                nums[idx] = val;
                for (int d = -1; d <= 1; ++d) {
                    int i = idx + d;
                    if (i > 0 && i < n-1) {
                        int was = is_peak[i];
                        int now = check(i);
                        if (was != now) { bit.add(i, now - was); is_peak[i] = now; }
                    }
                }
            }
        }
        return res;
    }
};
Go
 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
type Fenwick struct { bit []int }
func NewFenwick(n int) *Fenwick { return &Fenwick{make([]int, n+2)} }
func (f *Fenwick) Add(i, x int) { for i++; i < len(f.bit); i += i&-i { f.bit[i] += x } }
func (f *Fenwick) Sum(i int) int { s := 0; for i++; i > 0; i -= i&-i { s += f.bit[i] }; return s }
func (f *Fenwick) Range(l, r int) int { return f.Sum(r) - f.Sum(l-1) }
func processQueries(nums []int, queries [][]int) []int {
    n := len(nums)
    isPeak := make([]int, n)
    check := func(i int) int {
        if i > 0 && i < n-1 && nums[i] > nums[i-1] && nums[i] > nums[i+1] { return 1 }
        return 0
    }
    for i := 1; i < n-1; i++ { isPeak[i] = check(i) }
    bit := NewFenwick(n)
    for i := 0; i < n; i++ { if isPeak[i] == 1 { bit.Add(i, 1) } }
    res := []int{}
    for _, q := range queries {
        if q[0] == 1 {
            l, r := q[1], q[2]
            if r-l < 2 { res = append(res, 0) } else { res = append(res, bit.Range(l+1, r-1)) }
        } else {
            idx, val := q[1], q[2]
            nums[idx] = val
            for d := -1; d <= 1; d++ {
                i := idx + d
                if i > 0 && i < n-1 {
                    was, now := isPeak[i], check(i)
                    if was != now { bit.Add(i, now-was); isPeak[i] = now }
                }
            }
        }
    }
    return res
}
Java
 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
import java.util.*;
class Fenwick {
    int[] bit;
    Fenwick(int n) { bit = new int[n+2]; }
    void add(int i, int x) { for (++i; i < bit.length; i += i&-i) bit[i] += x; }
    int sum(int i) { int s = 0; for (++i; i > 0; i -= i&-i) s += bit[i]; return s; }
    int range(int l, int r) { return sum(r) - sum(l-1); }
}
class Solution {
    public List<Integer> processQueries(int[] nums, int[][] queries) {
        int n = nums.length;
        int[] isPeak = new int[n];
        java.util.function.IntPredicate check = i -> i > 0 && i < n-1 && nums[i] > nums[i-1] && nums[i] > nums[i+1];
        for (int i = 1; i < n-1; i++) isPeak[i] = check.test(i) ? 1 : 0;
        Fenwick bit = new Fenwick(n);
        for (int i = 0; i < n; i++) if (isPeak[i] == 1) bit.add(i, 1);
        List<Integer> res = new ArrayList<>();
        for (int[] q : queries) {
            if (q[0] == 1) {
                int l = q[1], r = q[2];
                if (r - l < 2) res.add(0);
                else res.add(bit.range(l+1, r-1));
            } else {
                int idx = q[1], val = q[2];
                nums[idx] = val;
                for (int d = -1; d <= 1; d++) {
                    int i = idx + d;
                    if (i > 0 && i < n-1) {
                        int was = isPeak[i], now = check.test(i) ? 1 : 0;
                        if (was != now) { bit.add(i, now - was); isPeak[i] = now; }
                    }
                }
            }
        }
        return res;
    }
}
Kotlin
 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
class Fenwick(n: Int) {
    private val bit = IntArray(n+2)
    fun add(i: Int, x: Int) { var idx = i+1; while (idx < bit.size) { bit[idx] += x; idx += idx and -idx } }
    fun sum(i: Int): Int { var idx = i+1; var s = 0; while (idx > 0) { s += bit[idx]; idx -= idx and -idx }; return s }
    fun range(l: Int, r: Int) = sum(r) - sum(l-1)
}
class Solution {
    fun processQueries(nums: IntArray, queries: Array<IntArray>): List<Int> {
        val n = nums.size
        val isPeak = IntArray(n)
        fun check(i: Int) = i > 0 && i < n-1 && nums[i] > nums[i-1] && nums[i] > nums[i+1]
        for (i in 1 until n-1) isPeak[i] = if (check(i)) 1 else 0
        val bit = Fenwick(n)
        for (i in 0 until n) if (isPeak[i] == 1) bit.add(i, 1)
        val res = mutableListOf<Int>()
        for (q in queries) {
            if (q[0] == 1) {
                val l = q[1]; val r = q[2]
                if (r - l < 2) res.add(0)
                else res.add(bit.range(l+1, r-1))
            } else {
                val idx = q[1]; val v = q[2]
                nums[idx] = v
                for (d in -1..1) {
                    val i = idx + d
                    if (i > 0 && i < n-1) {
                        val was = isPeak[i]; val now = if (check(i)) 1 else 0
                        if (was != now) { bit.add(i, now - was); isPeak[i] = now }
                    }
                }
            }
        }
        return res
    }
}
Python
 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
class Fenwick:
    def __init__(self, n):
        self.n = n+2
        self.bit = [0]*(n+2)
    def add(self, i, x):
        i += 1
        while i < self.n:
            self.bit[i] += x
            i += i & -i
    def sum(self, i):
        i += 1
        s = 0
        while i > 0:
            s += self.bit[i]
            i -= i & -i
        return s
    def range(self, l, r):
        return self.sum(r) - self.sum(l-1)

def processQueries(nums: list[int], queries: list[list[int]]) -> list[int]:
    n = len(nums)
    is_peak = [0]*n
    def check(i):
        return i > 0 and i < n-1 and nums[i] > nums[i-1] and nums[i] > nums[i+1]
    for i in range(1, n-1):
        is_peak[i] = check(i)
    bit = Fenwick(n)
    for i in range(n):
        if is_peak[i]: bit.add(i, 1)
    res = []
    for q in queries:
        if q[0] == 1:
            l, r = q[1], q[2]
            if r - l < 2:
                res.append(0)
            else:
                res.append(bit.range(l+1, r-1))
        else:
            idx, val = q[1], q[2]
            nums[idx] = val
            for d in [-1,0,1]:
                i = idx + d
                if 0 < i < n-1:
                    was, now = is_peak[i], check(i)
                    if was != now:
                        bit.add(i, now-was)
                        is_peak[i] = now
    return res
Rust
 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
struct Fenwick {
    bit: Vec<i32>, n: usize
}
impl Fenwick {
    fn new(n: usize) -> Self { Self { bit: vec![0; n+2], n: n+2 } }
    fn add(&mut self, mut i: usize, x: i32) { i += 1; while i < self.n { self.bit[i] += x; i += i & (!i+1) } }
    fn sum(&self, mut i: usize) -> i32 { i += 1; let mut s = 0; while i > 0 { s += self.bit[i]; i -= i & (!i+1) } s }
    fn range(&self, l: usize, r: usize) -> i32 { self.sum(r) - self.sum(l-1) }
}
fn process_queries(nums: &mut [i32], queries: &[Vec<i32>]) -> Vec<i32> {
    let n = nums.len();
    let mut is_peak = vec![0; n];
    let check = |i: usize, nums: &[i32]| i > 0 && i < n-1 && nums[i] > nums[i-1] && nums[i] > nums[i+1];
    for i in 1..n-1 { is_peak[i] = check(i, nums) as i32; }
    let mut bit = Fenwick::new(n);
    for i in 0..n { if is_peak[i] == 1 { bit.add(i, 1); } }
    let mut res = vec![];
    for q in queries {
        if q[0] == 1 {
            let (l, r) = (q[1] as usize, q[2] as usize);
            if r < l+2 { res.push(0); } else { res.push(bit.range(l+1, r-1)); }
        } else {
            let (idx, val) = (q[1] as usize, q[2]);
            nums[idx] = val;
            for d in [-1,0,1] {
                let i = idx as i32 + d;
                if i > 0 && (i as usize) < n-1 {
                    let i = i as usize;
                    let was = is_peak[i];
                    let now = check(i, nums) as i32;
                    if was != now { bit.add(i, now-was); is_peak[i] = now; }
                }
            }
        }
    }
    res
}
TypeScript
 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
class Fenwick {
    bit: number[]; n: number;
    constructor(n: number) { this.bit = new Array(n+2).fill(0); this.n = n+2; }
    add(i: number, x: number) { for (i++; i < this.n; i += i&-i) this.bit[i] += x; }
    sum(i: number) { let s = 0; for (i++; i > 0; i -= i&-i) s += this.bit[i]; return s; }
    range(l: number, r: number) { return this.sum(r) - this.sum(l-1); }
}
function processQueries(nums: number[], queries: number[][]): number[] {
    const n = nums.length;
    const isPeak = new Array(n).fill(0);
    const check = (i: number) => i > 0 && i < n-1 && nums[i] > nums[i-1] && nums[i] > nums[i+1];
    for (let i = 1; i < n-1; i++) isPeak[i] = check(i) ? 1 : 0;
    const bit = new Fenwick(n);
    for (let i = 0; i < n; i++) if (isPeak[i]) bit.add(i, 1);
    const res: number[] = [];
    for (const q of queries) {
        if (q[0] === 1) {
            const [_, l, r] = q;
            if (r - l < 2) res.push(0);
            else res.push(bit.range(l+1, r-1));
        } else {
            const [_, idx, val] = q;
            nums[idx] = val;
            for (let d = -1; d <= 1; d++) {
                const i = idx + d;
                if (i > 0 && i < n-1) {
                    const was = isPeak[i], now = check(i) ? 1 : 0;
                    if (was !== now) { bit.add(i, now - was); isPeak[i] = now; }
                }
            }
        }
    }
    return res;
}

Complexity

  • ⏰ Time complexity: O(Q log N) where Q is the number of queries and N is the array length
  • 🧺 Space complexity: O(N)