use crate::lib::ds::segtree::beats::*; use crate::lib::int::gcd::*; use crate::lib::io::*; use crate::lib::iter::Itertools; #[derive(Debug, Clone, Copy)] struct E { len: usize, sum: u64, max: u32, lcm: u32, } #[derive(Debug, Clone, Copy)] enum F { Asgn(u32), Gcd(u32), Unit, } use F::*; struct M; impl Alg for M { type Item = E; } impl Monoid for M { fn unit(&self) -> Self::Item { E { len: 0, sum: 0, max: 0, lcm: 1 } } fn op(&self, x: Self::Item, y: Self::Item) -> Self::Item { if x.len == 0 { y } else if y.len == 0 { x } else { E { len: x.len + y.len, sum: x.sum + y.sum, max: x.max.max(y.max), lcm: lcm(x.lcm, y.lcm), } } } } struct A; impl Alg for A { type Item = F; } impl Monoid for A { fn unit(&self) -> Self::Item { Unit } fn op(&self, x: Self::Item, y: Self::Item) -> Self::Item { match y { Asgn(_) => y, Gcd(y) => match x { Asgn(a) => Asgn(gcd(a, y)), Gcd(x) => Gcd(gcd(x, y)), _ => Gcd(y), }, _ => x, } } } fn lcm(x: u32, y: u32) -> u32 { let lcm = x as u64 * y as u64 / gcd(x, y) as u64; (1 << 30).min(lcm) as u32 } fn fill(a: u32, len: usize) -> E { E { len, sum: a as u64 * len as u64, max: a, lcm: a } } fn act(e: E, a: F) -> Option { match a { Asgn(a) => Some(fill(a, e.len)), Gcd(a) => if e.len == 1 { Some(fill(gcd(e.max, a), 1)) } else if e.lcm != 1 << 30 && a % e.lcm == 0 { Some(e) } else { None }, _ => Some(e), } } fn main() { let mut io = IO::new(); let [n, q]: [usize; 2] = io.scan(); let a = io .scan_iter::(n) .map(|a| E { len: 1, sum: a as u64, max: a, lcm: a }) .collect_vec(); let mut st = SegmentTreeBeats::from_slice(&a, M, A, act); for _ in 0..q { let (c, Usize1(l), r) = io.scan(); match c { 1 => { st.act_over(l, r, Asgn(io.scan())); }, 2 => { st.act_over(l, r, Gcd(io.scan())); }, 3 => { io.println(st.ask(l, r).max); }, _ => { io.println(st.ask(l, r).sum); }, } } } pub mod lib { pub mod alg { pub trait Alg { type Item: Copy; } pub trait Monoid: Alg { fn unit(&self) -> Self::Item; fn op(&self, x: Self::Item, y: Self::Item) -> Self::Item; fn op_to(&self, y: Self::Item, x: &mut Self::Item) { *x = self.op(*x, y); } } pub trait Group: Monoid { fn inv(&self, x: Self::Item) -> Self::Item; fn op_inv_to(&self, y: Self::Item, x: &mut Self::Item) { *x = self.op(*x, self.inv(y)) } } macro_rules! impl_monoid { ($target:ty, $($params:tt : $bounds:tt),*) => { impl<$($params : $bounds),*> Alg for $target { type Item = T; } impl<$($params : $bounds),*> Monoid for $target { fn unit(&self) -> Self::Item { (self.0)() } fn op(&self, x: Self::Item, y: Self::Item) -> Self::Item { (self.1)(x, y) } } }; } macro_rules! impl_group { ($target:ty, $($params:tt : $bounds:tt),*) => { impl_monoid!($target, $($params : $bounds),*); impl<$($params : $bounds),*> Group for $target { fn inv(&self, x: Self::Item) -> Self::Item { (self.2)(x) } } }; } pub struct MonoidImpl T, Op: Fn(T, T) -> T>(pub Unit, pub Op); pub struct GroupImpl(pub Unit, pub Op, pub Inv) where T: Copy, Unit: Fn() -> T, Op: Fn(T, T) -> T, Inv: Fn(T) -> T; // help! impl_monoid!(MonoidImpl, T: Copy, Unit: (Fn() -> T), Op: (Fn(T, T) -> T)); impl_group!(GroupImpl, T: Copy, Unit: (Fn() -> T), Op: (Fn(T, T) -> T), Inv: (Fn(T) -> T)); } // mod alg pub mod bit { use std::ops::*; pub trait Bits: Sized + BitAnd + BitAndAssign + BitOr + BitOrAssign + BitXor + BitXorAssign + Shl + ShlAssign + Shr + ShrAssign + Not { fn trailing_zeros(self) -> u32; fn lsb(self) -> Self; fn ilog2(self) -> u32; fn msb(self) -> Self; } macro_rules! impl_bit { ($($t:ty), *) => { $( impl Bits for $t { fn trailing_zeros(self) -> u32 { <$t>::trailing_zeros(self) } fn lsb(self) -> Self { self & self.wrapping_neg() } fn ilog2(self) -> u32 { std::mem::size_of::<$t>() as u32 * 8 - self.leading_zeros() - 1 } fn msb(self) -> Self { (1 as $t) << self.ilog2() } } )* }; } impl_bit!(i32, i64, i128, isize, u32, u64, u128, usize); } // mod bit pub mod cast { pub trait CastTo { fn cast_to(self) -> T; } pub trait CastFrom { fn cast_from(src: T) -> Self; } impl> CastFrom for T { fn cast_from(src: U) -> Self { U::cast_to(src) } } macro_rules! impl_prim { ($($ts:ty),*) => { impl_asint!({ $($ts),* } => { $($ts),* }); pub trait PrimCast where $(Self: CastTo<$ts>),*, $(Self: CastFrom<$ts>),* {} $( impl PrimCast for $ts {} )* } } macro_rules! impl_asint { ({ $t:ty } => { $($us:ty),* }) => { $( impl CastTo<$us> for $t { fn cast_to(self) -> $us { self as $us } } )* }; ({ $t:ty, $($ts:ty),* } => { $($us:ty),* }) => { impl_asint!({ $t } => { $($us),* }); impl_asint!({ $($ts),* } => { $($us),* }); }; } impl_prim!(i32, i64, i128, isize, u32, u64, u128, usize, f32, f64); pub trait As: Sized { fn as_>(self) -> T { T::cast_from(self) } fn into_>(self) -> T { T::from(self) } } impl As for T {} } // mod cast pub mod ds { pub mod segtree { pub mod beats { pub use crate::lib::alg::*; fn trunc(x: usize) -> usize { x >> x.trailing_zeros() } #[derive(Clone)] pub struct SegmentTreeBeats where Apply: Fn(On::Item, Act::Item) -> Option, { len: usize, log: u32, data: Vec<(On::Item, Act::Item)>, on_alg: On, act_alg: Act, apply: Apply, } impl Option> SegmentTreeBeats { pub fn new(len: usize, on_alg: On, act_alg: Act, apply: Apply) -> Self { Self { len, log: len.next_power_of_two().trailing_zeros(), data: vec![(on_alg.unit(), act_alg.unit()); len * 2], on_alg, act_alg, apply, } } pub fn from_slice(slice: &[On::Item], on_alg: On, act_alg: Act, apply: Apply) -> Self { let len = slice.len(); let log = len.next_power_of_two().trailing_zeros(); let iter = slice.iter().map(|&x| (x, act_alg.unit())); let mut data: Vec<_> = iter.clone().chain(iter).collect(); for i in (1..len).rev() { data[i].0 = on_alg.op(data[i << 1].0, data[i << 1 | 1].0); } Self { len, log, data, on_alg, act_alg, apply } } pub fn len(&self) -> usize { self.len } fn apply(&mut self, p: usize, actor: Act::Item) { self.act_alg.op_to(actor, &mut self.data[p].1); self.data[p].0 = if let Some(d) = (self.apply)(self.data[p].0, actor) { d } else { self.push(p); self.on_alg.op(self.data[p << 1].0, self.data[p << 1 | 1].0) }; } fn push(&mut self, p: usize) { self.apply(p << 1, self.data[p].1); self.apply(p << 1 | 1, self.data[p].1); self.data[p].1 = self.act_alg.unit(); } fn flush(&mut self, p: usize) { for s in (1..=self.log).rev() { self.push(p >> s); } } fn build(&mut self, mut p: usize) { p >>= 1; while p != 0 { self.data[p].0 = self.on_alg.op(self.data[p << 1].0, self.data[p << 1 | 1].0); // debug_assert_eq!(self.data[p].1, self.act_alg.unit()); p >>= 1; } } pub fn ask(&mut self, l: usize, r: usize) -> On::Item { self.flush(trunc(l + self.len())); self.flush(trunc(r + self.len()) - 1); let [mut resl, mut resr] = [self.on_alg.unit(); 2]; let (mut l, mut r) = (l + self.len(), r + self.len()); while l < r { if l & 1 != 0 { resl = self.on_alg.op(resl, self.data[l].0); l += 1; } if r & 1 != 0 { r -= 1; resr = self.on_alg.op(self.data[r].0, resr); } l >>= 1; r >>= 1; } self.on_alg.op(resl, resr) } pub fn exec(&mut self, pos: usize, f: F) { self.flush(pos + self.len()); let p = pos + self.len(); f(&mut self.data[p].0); self.build(pos + self.len()); } pub fn act_over(&mut self, l: usize, r: usize, actor: Act::Item) { self.flush(trunc(l + self.len())); self.flush(trunc(r + self.len()) - 1); { let (mut l, mut r) = (l + self.len(), r + self.len()); while l < r { if l & 1 != 0 { self.apply(l, actor); l += 1; } if r & 1 != 0 { r -= 1; self.apply(r, actor); } l >>= 1; r >>= 1; } } self.build(trunc(l + self.len())); self.build(trunc(r + self.len()) - 1); } } } // mod beats } // mod segtree } // mod ds pub mod int { use crate::lib::bit::*; use crate::lib::cast::*; pub use crate::lib::num::*; pub use crate::lib::zo::*; use std::ops::*; pub trait Int: Num + Ord + Rem + RemAssign + Bits + PrimCast { type Signed: IInt + CastFrom + CastTo; type Unsigned: UInt + CastFrom + CastTo; const MIN: Self; const MAX: Self; fn abs(self) -> Self::Unsigned; fn rem_euclid(self, rhs: Self::Unsigned) -> Self::Unsigned; } pub trait IInt: Int + INum {} pub trait UInt: Int {} macro_rules! impl_int { (@ $t:ident, $i:ident, $u:ident) => { impl Int for $t { type Signed = $i; type Unsigned = $u; const MIN: Self = std::$t::MIN; const MAX: Self = std::$t::MAX; #[allow(unconditional_recursion)] // it's not fn abs(self) -> Self::Unsigned { self.abs() as $u } fn rem_euclid(self, rhs: Self::Unsigned) -> Self::Unsigned { <$t>::rem_euclid(self, rhs as $t) as $u } } }; ({ $i:ident }, { $u:ident }) => { impl_int!(@ $i, $i, $u); impl_int!(@ $u, $i, $u); impl IInt for $i {} impl UInt for $u {} }; ({ $i:ident, $($is:ident),* }, { $u:ident, $($us:ident),* }) => { impl_int!({ $i }, { $u }); impl_int!({ $($is),* }, { $($us),* }); } } impl_int!({ i32, i64, i128, isize }, { u32, u64, u128, usize }); pub mod gcd { use super::*; pub fn gcd(a: I, b: I) -> I { if b == I::ZERO { a } else { gcd(b, a % b) } // ugcd(a.abs(), b.abs()).as_() } // binary gcd pub fn ugcd(mut a: I, mut b: I) -> I { if a.is_zero() { return b; } else if b.is_zero() { return a; } let a_shift = a.trailing_zeros(); a >>= a_shift; let b_shift = b.trailing_zeros(); b >>= b_shift; let shift = a_shift.min(b_shift); loop { if a > b { std::mem::swap(&mut a, &mut b); } b -= a; if b.is_zero() { return a << shift; } b >>= b.trailing_zeros(); } } /// (x, y, g) where ax + by = g, x >= 0 pub fn extgcd(mut a: I, mut b: I) -> (I, I, I) { // A = [a, x, y; b, u, v], k = [-1; a0; b0] // A'= [a, x, y; 0, u, v] \therefore a0*u + b0*v = 0 let (mut x, mut y, mut u, mut v) = (I::ONE, I::ZERO, I::ZERO, I::ONE); while !b.is_zero() { let t = a / b; a -= t * b; x -= t * u; y -= t * v; std::mem::swap(&mut a, &mut b); std::mem::swap(&mut x, &mut u); std::mem::swap(&mut y, &mut v); } if x < I::ZERO { x += u; y -= v; debug_assert_eq!(gcd(u, v), I::ONE); debug_assert!(x + u >= I::ZERO); } (x, y, a) } } // mod gcd } // mod int pub mod io { use std::io::{stdout, BufWriter, Read, StdoutLock, Write}; use std::marker::PhantomData; pub struct IO { iter: std::str::SplitAsciiWhitespace<'static>, buf: BufWriter>, } impl IO { pub fn new() -> Self { let mut input = String::new(); std::io::stdin().read_to_string(&mut input).unwrap(); let input = Box::leak(input.into_boxed_str()); let out = Box::leak(Box::new(stdout())); IO { iter: input.split_ascii_whitespace(), buf: BufWriter::new(out.lock()), } } fn scan_str(&mut self) -> &'static str { self.iter.next().unwrap() } fn scan_raw(&mut self) -> &'static [u8] { self.scan_str().as_bytes() } pub fn scan(&mut self) -> T { T::scan(self) } pub fn scan_iter(&mut self, n: usize) -> std::iter::Take> { Iter { io: self, _m: PhantomData }.take(n) } pub fn scan_vec(&mut self, n: usize) -> Vec { (0..n).map(|_| self.scan()).collect() } pub fn print(&mut self, x: T) { T::print(self, x); } pub fn println(&mut self, x: T) { self.print(x); self.print("\n"); } pub fn iterln>(&mut self, into_iter: I, delim: &str) { let mut iter = into_iter.into_iter(); if let Some(v) = iter.next() { self.print(v); for v in iter { self.print(delim); self.print(v); } } self.print("\n"); } pub fn flush(&mut self) { self.buf.flush().unwrap(); } } pub struct Iter<'a, T> { io: &'a mut IO, _m: PhantomData, } impl Iterator for Iter<'_, T> { type Item = T; fn next(&mut self) -> Option { Some(self.io.scan()) } } pub trait Scan { fn scan(io: &mut IO) -> Self; } pub trait Print { fn print(w: &mut IO, x: Self); } macro_rules! impl_parse_iint { ($($t:ty),*) => { $( impl Scan for $t { fn scan(s: &mut IO) -> Self { let scan = |t: &[u8]| t.iter().fold(0, |s, &b| s * 10 + (b & 0x0F) as $t); let s = s.scan_raw(); if let Some((&b'-', t)) = s.split_first() { -scan(t) } else { scan(s) } } } )* }; } macro_rules! impl_parse_uint { ($($t:ty),*) => { $( impl Scan for $t { fn scan(s: &mut IO) -> Self { s.scan_raw().iter().fold(0, |s, &b| s * 10 + (b & 0x0F) as $t) } } )* }; } impl_parse_iint!(i32, i64, i128, isize); impl_parse_uint!(u32, u64, u128, usize); impl Scan for u8 { fn scan(s: &mut IO) -> Self { let bytes = s.scan_raw(); debug_assert_eq!(bytes.len(), 1); bytes[0] } } impl Scan for &[u8] { fn scan(s: &mut IO) -> Self { s.scan_raw() } } impl Scan for Vec { fn scan(s: &mut IO) -> Self { s.scan_raw().to_vec() } } macro_rules! impl_tuple { () => {}; ($t:ident $($ts:ident)*) => { impl<$t: Scan, $($ts: Scan),*> Scan for ($t, $($ts),*) { fn scan(s: &mut IO) -> Self { ($t::scan(s), $($ts::scan(s)),*) } } impl<$t: Print, $($ts: Print),*> Print for ($t, $($ts),*) { #[allow(non_snake_case)] fn print(w: &mut IO, ($t, $($ts),*): Self) { w.print($t); $( w.print(" "); w.print($ts); )* } } impl_tuple!($($ts)*); }; } impl_tuple!(A B C D E F G); macro_rules! impl_scan_array { () => {}; ($n:literal $($ns:literal)*) => { impl Scan for [T; $n] { fn scan(s: &mut IO) -> Self { let mut scan = |_| T::scan(s); [scan($n), $(scan($ns)),*] } } impl_scan_array!($($ns)*); }; } impl_scan_array!(7 6 5 4 3 2 1); macro_rules! impl_print_prim { ($($t:ty),*) => { $( impl Print for $t { fn print(w: &mut IO, x: Self) { w.buf.write_all(format!("{:.10}", x).as_bytes()).unwrap(); } } impl Print for &$t { fn print(w: &mut IO, x: Self) { w.print(*x); } } )* }; } impl_print_prim!(i32, i64, i128, isize, u32, u64, u128, usize, f32, f64); impl Print for u8 { fn print(w: &mut IO, x: Self) { w.buf.write_all(&[x]).unwrap(); } } impl Print for &[u8] { fn print(w: &mut IO, x: Self) { w.buf.write_all(x).unwrap(); } } impl Print for Vec { fn print(w: &mut IO, x: Self) { w.buf.write_all(&x).unwrap(); } } impl Print for &str { fn print(w: &mut IO, x: Self) { w.print(x.as_bytes()); } } #[derive(Debug, Clone, Copy, Default)] pub struct Usize1(pub usize); impl Scan for Usize1 { fn scan(io: &mut IO) -> Self { let n: usize = io.scan(); Self(n - 1) } } impl Print for Usize1 { fn print(w: &mut IO, x: Self) { w.print(x.0 + 1) } } } // mod io pub mod iter { pub trait Itertools: Iterator { fn collect_vec(self) -> Vec where Self: Sized, { self.collect() } } impl Itertools for I {} #[macro_export] macro_rules! iprod { ($head:expr) => { $head.into_iter() }; ($head:expr, $($tail:expr),*) => ( $head.into_iter().flat_map(|e| { std::iter::repeat(e).zip(iprod!($($tail),*)) }) ); } } // mod iter pub mod num { pub use crate::lib::zo::ZeroOne; use std::fmt::*; use std::ops::*; pub trait Num: ZeroOne + Add + AddAssign + Sub + SubAssign + Mul + MulAssign + Div + DivAssign + Debug + Display { fn wrapping_add(self, rhs: Self) -> Self; fn wrapping_neg(self) -> Self; } pub trait INum: Num + Neg {} macro_rules! impl_num { ($($t:ty),*) => { $( impl Num for $t { fn wrapping_add(self, rhs: Self) -> Self { self.wrapping_add(rhs) } fn wrapping_neg(self) -> Self { self.wrapping_neg() } } )* }; } impl_num!(i32, i64, i128, isize, u32, u64, u128, usize); impl> INum for T {} } // mod num pub mod zo { pub trait ZeroOne: Copy + Eq { const ZERO: Self; fn is_zero(self) -> bool { self == Self::ZERO } const ONE: Self; } macro_rules! impl_zo { ($($t:ty),*) => { $( impl ZeroOne for $t { const ZERO: Self = 0; const ONE: Self = 1; } )* }; } impl_zo!(i32, i64, i128, isize, u32, u64, u128, usize); } // mod zo } // mod lib