use std::cmp::*; use std::collections::*; use std::fmt::Debug; use std::io::BufRead; use std::io::{stdin, Read}; use std::ops::{Add, Sub}; use std::str::FromStr; #[derive(Eq, PartialEq, Clone, Debug)] pub struct Rev(pub T); impl PartialOrd for Rev { fn partial_cmp(&self, other: &Rev) -> Option { other.0.partial_cmp(&self.0) } } impl Ord for Rev { fn cmp(&self, other: &Rev) -> Ordering { other.0.cmp(&self.0) } } fn read() -> T { let stdin = stdin(); let stdin = stdin.lock(); let token: String = stdin .bytes() .map(|c| c.expect("failed to read char") as char) .skip_while(|c| c.is_whitespace()) .take_while(|c| !c.is_whitespace()) .collect(); token.parse().ok().expect("failed to parse token") } macro_rules! read { (($($t:tt),*)) => { ( $(read!($t)),* ) }; ([[$t:tt; $len1:expr]; $len2:expr]) => { (0..$len2).map(|_| read!([$t; $len1])).collect::>() }; ([$t:tt; $len:expr]) => { (0..$len).map(|_| read!($t)).collect::>() }; (chars) => { read!(String).chars().collect::>() }; (usize1) => { read!(usize) - 1 }; ($t:ty) => {{ let stdin = stdin(); let stdin = stdin.lock(); let token: String = stdin .bytes() .map(|c| c.unwrap() as char) .skip_while(|c| c.is_whitespace()) .take_while(|c| !c.is_whitespace()) .collect(); token.parse::<$t>().unwrap() }}; } macro_rules! input { (mut $name:ident: $t:tt, $($r:tt)*) => { let mut $name = read!($t); $(println!("{}", stringify!($r));)* input!($($r)*); }; (mut $name:ident: $t:tt) => { let mut $name = read!($t); }; ($name:ident: $t:tt, $($r:tt)*) => { let $name = read!($t); input!($($r)*); }; ($name:ident: $t:tt) => { let $name = read!($t); }; } trait VecExt { fn cumulation(&self) -> Vec; fn cumulation_query(&self, a: usize, b: usize) -> i64; } impl VecExt for Vec { fn cumulation(&self) -> Vec { let mut vec = vec![0; self.len() + 1]; for i in 0..self.len() { vec[i + 1] = self[i] + vec[i]; } return vec; } fn cumulation_query(&self, left: usize, right: usize) -> i64 { return self[right] - self[left]; } } pub trait Monoid { type T: Copy + Clone + std::fmt::Debug + PartialOrd; fn op(lhs: &Self::T, rhs: &Self::T) -> Self::T; fn identity() -> Self::T; } pub trait OperatorMonoid { type T; type U: Copy + Clone + std::fmt::Debug + PartialOrd; fn op1(lhs: &Self::U, rhs: &Self::U) -> Self::U; fn op2(lhs: &Self::T, rhs: &Self::U, len: &usize) -> Self::T; fn identity() -> Self::U; } #[derive(Clone)] struct Sum; impl Monoid for Sum { type T = i64; fn identity() -> Self::T { return 0; } fn op(a: &Self::T, b: &Self::T) -> Self::T { return a + b; } } #[derive(Clone)] struct Max {} impl Monoid for Max { type T = i64; fn identity() -> Self::T { return 0 } fn op(lhs: &Self::T, rhs: &Self::T) -> Self::T { return std::cmp::max(*lhs, *rhs); } } #[derive(Clone)] struct OperatorMax {} impl OperatorMonoid for OperatorMax { type T = i64; type U = Option; fn identity() -> Self::U { return None; } fn op1(_query: &Self::U, rhs: &Self::U) -> Self::U { return *rhs } fn op2(lhs: &Self::T, rhs: &Self::U, _: &usize) -> Self::T { if rhs.is_some() { (*rhs).unwrap() } else { *lhs } } } #[derive(Clone)] struct Min {} impl Monoid for Min { type T = i64; fn identity() -> Self::T { return (1 << 31) - 1 } fn op(lhs: &Self::T, rhs: &Self::T) -> Self::T { return std::cmp::min(*lhs, *rhs); } } #[derive(Clone)] struct OperatorMin {} impl OperatorMonoid for OperatorMin { type T = i64; type U = Option; fn identity() -> Self::U { return None; } fn op1(_: &Self::U, rhs: &Self::U) -> Self::U { return *rhs } fn op2(lhs: &Self::T, rhs: &Self::U, _: &usize) -> Self::T { if rhs.is_some() { (*rhs).unwrap() } else { *lhs } } } #[derive(Debug)] pub struct LazySegmentTree> { n: usize, size: usize, data: Vec, lazy: Vec, } impl> LazySegmentTree { pub fn new(n: usize) -> LazySegmentTree { let mut size = 1; while size < n { size *= 2; } LazySegmentTree { n: n, size: size, data: vec![M::identity(); size * 2], lazy: vec![O::identity(); size * 2], } } pub fn set(&mut self, k: usize, v: M::T) { self.data[k + self.size] = v; } pub fn build(&mut self) { for k in (1..self.size - 1).rev() { self.data[k] = M::op(&self.data[k * 2], &self.data[k * 2 + 1]); } } pub fn propagate(&mut self, k: usize, len: usize) { if self.lazy[k] != O::identity() { self.data[k] = O::op2(&self.data[k], &self.lazy[k], &len); if k < self.size { self.lazy[2 * k + 0] = O::op1(&self.lazy[2 * k + 0], &self.lazy[k]); self.lazy[2 * k + 1] = O::op1(&self.lazy[2 * k + 1], &self.lazy[k]); } self.lazy[k] = O::identity(); } } pub fn _update(&mut self, a: usize, b: usize, x: O::U, k: usize, l: usize, r: usize) { self.propagate(k, r - l); if r <= a || b <= l { return; } else if a <= l && r <= b { self.lazy[k] = O::op1(&self.lazy[k], &x); self.propagate(k, r - l); } else { self._update(a, b, x, 2 * k + 0, l, (l + r) >> 1); self._update(a, b, x, 2 * k + 1, (l + r) >> 1, r); self.data[k] = M::op(&self.data[2 * k + 0], &self.data[2 * k + 1]); } } pub fn update(&mut self, a: usize, b: usize, x: O::U) { let sz = self.size; self._update(a, b, x, 1, 0, sz); } fn _query(&mut self, a: usize, b: usize, k: usize, l: usize, r: usize) -> M::T { self.propagate(k, r - l); if r <= a || b <= l { return M::identity(); } else if a <= l && r <= b { return self.data[k]; } else { return M::op( &self._query(a, b, 2 * k + 0, l, (l + r) >> 1), &self._query(a, b, 2 * k + 1, (l + r) >> 1, r), ); } } pub fn query(&mut self, a: usize, b: usize) -> M::T { let sz = self.size; return self._query(a, b, 1, 0, sz); } } #[derive(Clone)] struct Hoge {} impl Monoid for Hoge { type T = (i64, i64); fn identity() -> Self::T { (0, 0) } fn op(lhs: &Self::T, rhs: &Self::T) -> Self::T { (lhs.0 + rhs.0, lhs.1 + rhs.1) } } #[derive(Clone)] struct OperatorHoge {} impl OperatorMonoid for OperatorHoge { type T = (i64, i64); type U = i64; fn identity() -> Self::U { -1 } fn op1(_: &Self::U, rhs: &Self::U) -> Self::U { *rhs } fn op2(lhs: &Self::T, rhs: &Self::U, len: &usize) -> Self::T { match rhs { 1 => (*len as i64, 0), 2 => (0, *len as i64), _ => *lhs, } } } fn main() { input!(n: usize, q: usize); let mut seg: LazySegmentTree = LazySegmentTree::new(n); let mut sum_a = 0; let mut sum_b = 0; for _ in 0..q { input!(x: usize, l: usize, mut r: usize); r += 1; if x == 0 { let cnt = seg.query(l, r); if cnt.0 > cnt.1 { sum_a += cnt.0; } else if cnt.0 < cnt.1 { sum_b += cnt.1; } } else if x == 1 { seg.update(l, r, 1); } else { seg.update(l, r, 2); } } let cnt = seg.query(0, n); println!("{} {}", sum_a + cnt.0, sum_b + cnt.1); }