Skip to main content
Back to problems
#3569
Hard Algorithms

Maximize count of distinct primes after split

Array Math Segment Tree Number Theory
18.4% acceptance
Feb 25, 2026
24
7
You are given integer array nums and 2D integer array queries where queries[i] = [idx, val]. For each query: update nums[idx]=val, then choose k (1<=k

Solution

Rust
Time O(n²)
Space O(n)
LeetCode
solution.rs
use std::collections::BTreeSet;

struct SegTree {
  n: usize,
  tree: Vec<i32>,
  lazy: Vec<i32>,
}

impl SegTree {
  fn new(n: usize) -> Self {
    let size = 4 * (n + 1);
    SegTree { n, tree: vec![0; size], lazy: vec![0; size] }
  }

  fn push_down(&mut self, node: usize) {
    let v = self.lazy[node];
    if v != 0 {
      for &c in &[2 * node, 2 * node + 1] {
        self.tree[c] += v;
        self.lazy[c] += v;
      }
      self.lazy[node] = 0;
    }
  }

  fn range_add(&mut self, l: usize, r: usize, val: i32) {
    if l > r { return; }
    let n = self.n;
    self.range_add_inner(1, 0, n - 1, l, r, val);
  }

  fn range_add_inner(&mut self, node: usize, nl: usize, nr: usize, l: usize, r: usize, val: i32) {
    if l > nr || r < nl { return; }
    if l <= nl && nr <= r {
      self.tree[node] += val;
      self.lazy[node] += val;
      return;
    }
    self.push_down(node);
    let mid = (nl + nr) / 2;
    self.range_add_inner(2 * node, nl, mid, l, r, val);
    self.range_add_inner(2 * node + 1, mid + 1, nr, l, r, val);
    self.tree[node] = self.tree[2 * node].max(self.tree[2 * node + 1]);
  }

  fn max_query(&mut self, l: usize, r: usize) -> i32 {
    if l > r { return 0; }
    let n = self.n;
    self.max_query_inner(1, 0, n - 1, l, r)
  }

  fn max_query_inner(&mut self, node: usize, nl: usize, nr: usize, l: usize, r: usize) -> i32 {
    if l > nr || r < nl { return 0; }
    if l <= nl && nr <= r { return self.tree[node]; }
    self.push_down(node);
    let mid = (nl + nr) / 2;
    self.max_query_inner(2 * node, nl, mid, l, r)
      .max(self.max_query_inner(2 * node + 1, mid + 1, nr, l, r))
  }
}

impl Solution {
  pub fn maximum_count(mut nums: Vec<i32>, queries: Vec<Vec<i32>>) -> Vec<i32> {
    const LIMIT: usize = 100001;
    let mut is_prime = vec![true; LIMIT];
    is_prime[0] = false;
    is_prime[1] = false;
    let mut i = 2;
    while i * i < LIMIT {
      if is_prime[i] {
        let mut j = i * i;
        while j < LIMIT {
          is_prime[j] = false;
          j += i;
        }
      }
      i += 1;
    }

    let n = nums.len();
    // For each prime value, maintain a sorted set of all positions it occupies.
    let mut positions: Vec<BTreeSet<usize>> = vec![BTreeSet::new(); LIMIT];
    let mut seg = SegTree::new(n);
    let mut distinct_primes = 0i32;

    // Activate the current (min,max) range of prime v in the seg tree.
    let activate = |positions: &Vec<BTreeSet<usize>>, seg: &mut SegTree, v: usize, delta: i32| {
      let s = &positions[v];
      if s.len() >= 2 {
        let mn = *s.iter().next().unwrap();
        let mx = *s.iter().next_back().unwrap();
        seg.range_add(mn + 1, mx, delta);
      }
    };

    // Build initial state
    for (idx, &v) in nums.iter().enumerate() {
      let v = v as usize;
      if v < LIMIT && is_prime[v] {
        activate(&positions, &mut seg, v, -1); // remove old range (harmless if empty)
        let was_empty = positions[v].is_empty();
        positions[v].insert(idx);
        if was_empty { distinct_primes += 1; }
        activate(&positions, &mut seg, v, 1);
      }
    }

    let mut result = Vec::with_capacity(queries.len());

    for q in &queries {
      let idx = q[0] as usize;
      let new_val = q[1] as usize;
      let old_val = nums[idx] as usize;

      // Remove old value at idx
      if old_val < LIMIT && is_prime[old_val] {
        activate(&positions, &mut seg, old_val, -1);
        positions[old_val].remove(&idx);
        if positions[old_val].is_empty() {
          distinct_primes -= 1;
        } else {
          activate(&positions, &mut seg, old_val, 1);
        }
      }

      nums[idx] = new_val as i32;

      // Add new value at idx
      if new_val < LIMIT && is_prime[new_val] {
        activate(&positions, &mut seg, new_val, -1);
        let was_empty = positions[new_val].is_empty();
        positions[new_val].insert(idx);
        if was_empty { distinct_primes += 1; }
        activate(&positions, &mut seg, new_val, 1);
      }

      let bonus = seg.max_query(1, n - 1);
      result.push(distinct_primes + bonus);
    }

    result
  }
}