fn main() { let (a, ask) = read_input(); let ini = a.iter().map(|a| Node::new(*a as u64)).collect::>(); let mut seg = SegmentTree::new(R, ini); use std::io::*; let out = std::io::stdout(); let mut out = std::io::BufWriter::new(out.lock()); for query in ask { match query { Query::Assign(l, r, v) => { let v = v as u64; seg.update(l, r, |node| node.set(v)); } Query::Chgcd(l, r, v) => { let v = v as u64; seg.update_bool(l, r, |node| { if v % node.lcm == 0 { return true; } node.max * node.len == node.sum && { node.set(binary_gcd(node.max, v)); true } }) } Query::Max(l, r) => { let mut ans = 0u64; seg.find(l, r, |node| ans = ans.max(node.max)); writeln!(out, "{}", ans).ok(); } Query::Sum(l, r) => { let mut ans = 0u64; seg.find(l, r, |node| ans += node.sum); writeln!(out, "{}", ans).ok(); } } } } #[derive(Clone)] struct Node { len: u64, sum: u64, max: u64, lcm: u64, } impl Node { fn new(a: u64) -> Self { Node { len: 1, sum: a, max: a, lcm: a, } } fn set(&mut self, v: u64) { self.sum = v * self.len; self.max = v; self.lcm = v; } } fn lcm(a: u64, b: u64) -> u64 { const INF: u64 = 1_000_000_001; if a == INF || b == INF { INF } else { INF.min(a / binary_gcd(a, b) * b) } } struct R; impl DFSNode for R { type T = Node; fn merge(&self, p: &mut Self::T, c: &[Self::T]) { let (l, r) = (&c[0], &c[1]); p.len = l.len + r.len; p.sum = l.sum + r.sum; p.max = l.max.max(r.max); p.lcm = lcm(l.lcm, r.lcm); } fn push(&self, p: &mut Self::T, c: &mut [Self::T]) { if p.len * p.max == p.sum { let v = p.max; for c in c.iter_mut() { c.set(v); } } } } enum Query { Assign(usize, usize, u32), Chgcd(usize, usize, u32), Max(usize, usize), Sum(usize, usize), } fn read_input() -> (Vec, Vec) { let mut s = String::new(); use std::io::*; std::io::stdin().read_to_string(&mut s).unwrap(); let mut it = s.trim().split_whitespace().flat_map(|s| s.parse::()); let mut next = || it.next().unwrap(); let n = next(); let q = next(); let a = (0..n).map(|_| next() as u32).collect(); let ask = (0..q) .map(|_| { let op = next(); let l = next() - 1; let r = next(); match op { 1 => { let x = next() as u32; Query::Assign(l, r, x) } 2 => { let x = next() as u32; Query::Chgcd(l, r, x) } 3 => Query::Max(l, r), _ => Query::Sum(l, r), } }) .collect(); (a, ask) } pub trait DFSNode { type T: Clone; fn merge(&self, p: &mut Self::T, c: &[Self::T]); fn push(&self, p: &mut Self::T, c: &mut [Self::T]); } pub struct SegmentTree { op: R, data: Vec, size: usize, n: usize, } impl SegmentTree { pub fn new(op: R, ini: Vec) -> Self { assert!(ini.len() > 0); let n = ini.len(); let size = n.next_power_of_two(); let mut data = vec![ini[0].clone(); 2 * size]; for (data, ini) in data[size..].iter_mut().zip(ini) { *data = ini; } for i in (1..size).rev() { let (f, t) = data.split_at_mut(2 * i); op.merge(&mut f[i], &t[..2]); } SegmentTree { op, data, size, n } } pub fn update(&mut self, l: usize, r: usize, mut f: F) where F: FnMut(&mut R::T), { assert!(l <= r && r <= self.n); if l == r { return; } self.dfs(1, 0, self.size, l, r, true, &mut |node| { f(node); true }); } pub fn update_bool(&mut self, l: usize, r: usize, mut f: F) where F: FnMut(&mut R::T) -> bool, { assert!(l <= r && r <= self.n); if l == r { return; } self.dfs(1, 0, self.size, l, r, true, &mut f); } pub fn find(&mut self, l: usize, r: usize, mut f: F) where F: FnMut(&R::T), { assert!(l <= r && r <= self.n); if l == r { return; } self.dfs(1, 0, self.size, l, r, false, &mut |node| { f(node); true }); } fn dfs(&mut self, v: usize, l: usize, r: usize, x: usize, y: usize, update: bool, f: &mut F) where F: FnMut(&mut R::T) -> bool, { if x <= l && r <= y && f(&mut self.data[v]) { return; } if r <= self.n { let (f, t) = self.data.split_at_mut(2 * v); self.op.push(&mut f[v], &mut t[..2]); } let m = (l + r) / 2; if x < m { self.dfs(2 * v, l, m, x, y, update, f); } if m < y { self.dfs(2 * v + 1, m, r, x, y, update, f); } if update && r <= self.n { let (f, t) = self.data.split_at_mut(2 * v); self.op.merge(&mut f[v], &t[..2]); } } } // ---------- begin binary_gcd ---------- pub fn binary_gcd(a: u64, b: u64) -> u64 { if a == 0 || b == 0 { return a + b; } let x = a.trailing_zeros(); let y = b.trailing_zeros(); let mut a = a >> x; let mut b = b >> y; while a != b { let x = (a ^ b).trailing_zeros(); if a < b { std::mem::swap(&mut a, &mut b); } a = (a - b) >> x; } a << x.min(y) } // ---------- end binary_gcd ----------