実装上の注意点
- 更新の演算でバグらせないように気をつける。今回の場合、「ゼロクリア」と「区間加算」を同時に処理する構造を考えようとするとバグらせるに決まっているので、両方を含む代数構造を考えるとよい。
提出: Submission #4309587 - 全国統一プログラミング王決定戦本戦 (Rust)
/**
* Lazy Segment Tree. This data structure is useful for fast folding and updating on intervals of an array
* whose elements are elements of monoid T. Note that constructing this tree requires the identity
* element of T and the operation of T. This is monomorphised, because of efficiency. T := i64, biop = max, upop = (+)
* Reference: http://d.hatena.ne.jp/kyuridenamida/20121114/1352835261
* Verified by https://codeforces.com/contest/1114/submission/49759034
*/
pub trait ActionRing {
type T: Clone + Copy;
type U: Clone + Copy + PartialEq + Eq;
fn biop(Self::T, Self::T) -> Self::T;
fn update(Self::T, Self::U, height: usize) -> Self::T;
fn upop(Self::U, Self::U) -> Self::U;
fn e() -> Self::T;
fn upe() -> Self::U;
}
pub struct LazySegTree<R: ActionRing> {
n: usize,
dep: usize,
dat: Vec<R::T>,
lazy: Vec<R::U>,
}
impl<R: ActionRing> LazySegTree<R> {
pub fn new(n_: usize) -> Self {
let mut n = 1;
let mut dep = 0;
while n < n_ { n *= 2; dep += 1; }
LazySegTree {
n: n,
dep: dep,
dat: vec![R::e(); 2 * n - 1],
lazy: vec![R::upe(); 2 * n - 1]
}
}
#[inline]
fn lazy_evaluate_node(&mut self, k: usize, height: usize) {
if self.lazy[k] == R::upe() { return; }
self.dat[k] = R::update(self.dat[k], self.lazy[k], height);
if k < self.n - 1 {
self.lazy[2 * k + 1] = R::upop(self.lazy[2 * k + 1], self.lazy[k]);
self.lazy[2 * k + 2] = R::upop(self.lazy[2 * k + 2], self.lazy[k]);
}
self.lazy[k] = R::upe();
}
#[inline]
fn update_node(&mut self, k: usize) {
self.dat[k] = R::biop(self.dat[2 * k + 1], self.dat[2 * k + 2]);
}
fn update_sub(&mut self, a: usize, b: usize, v: R::U, k: usize, height: usize, l: usize, r: usize) {
self.lazy_evaluate_node(k, height);
if r <= a || b <= l {return;}
if a <= l && r <= b {
self.lazy[k] = R::upop(self.lazy[k], v);
self.lazy_evaluate_node(k, height);
return;
}
self.update_sub(a, b, v, 2 * k + 1, height - 1, l, (l + r) / 2);
self.update_sub(a, b, v, 2 * k + 2, height - 1, (l + r) / 2, r);
self.update_node(k);
}
#[inline]
pub fn update(&mut self, a: usize, b: usize, v: R::U) {
let n = self.n;
let dep = self.dep;
self.update_sub(a, b, v, 0, dep, 0, n);
}
fn query_sub(&mut self, a: usize, b: usize, k: usize, height: usize, l: usize, r: usize) -> R::T {
self.lazy_evaluate_node(k, height);
if r <= a || b <= l {return R::e();}
if a <= l && r <= b {return self.dat[k];}
let vl = self.query_sub(a, b, 2 * k + 1, height - 1, l, (l + r) / 2);
let vr = self.query_sub(a, b, 2 * k + 2, height - 1, (l + r) / 2, r);
self.update_node(k);
R::biop(vl, vr)
}
#[inline]
pub fn query(&mut self, a: usize, b: usize) -> R::T {
let n = self.n;
let dep = self.dep;
self.query_sub(a, b, 0, dep, 0, n)
}
}
struct Monoid {}
impl ActionRing for Monoid {
type T = i64;
type U = (i64, i64);
fn e() -> i64 { 0 }
fn upe() -> Self::U { (1, 0) }
fn biop(a: i64, b: i64) -> i64 {
a + b
}
fn update(a: Self::T, (b, c): Self::U, height: usize) -> i64 {
a * b + (c << height)
}
fn upop((a, b): Self::U, (c, d): Self::U) -> Self::U {
(a * c, b * c + d)
}
}
fn solve() {
let out = std::io::stdout();
let mut out = BufWriter::new(out.lock());
macro_rules! puts {
($format:expr) => (write!(out,$format).unwrap());
($format:expr, $($args:expr),+) => (write!(out,$format,$($args),*).unwrap())
}
input! {
n: usize,
tlr: [(i64, usize1, usize)],
}
let mut st = LazySegTree::<Monoid>::new(n);
let mut last_t = 0;
let mut tot = 0;
for (t, l, r) in tlr {
let diff = t - last_t;
st.update(0, n, (1, diff));
tot += st.query(l, r);
st.update(l, r, (0, 0));
last_t = t;
}
puts!("{}\n", tot);
}