0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Rust で ACL の LazySegtree を使う。

Last updated at Posted at 2025-02-14

Rust で ACL の LazySegtree を使う

AtCoder Library (ACL) に含まれる LazySegtree は、遅延伝播セグメントツリー (Lazy Segment Tree) を簡単に利用できる便利なデータ構造です。本記事では、Rust で ACL の LazySegtree を使う方法を解説します。

前提知識

LazySegtree を理解するために、以下の記事を読むことを推奨します。

LazySegtree の基本構造

ACL の LazySegtree は、

  • 作用モノイド (MapMonoid)
  • データモノイド (Monoid)

の 2 つを定義する必要があります。

LazySegtree の型パラメータと、ACL C++ 版の引数との対応は以下の通りです。

C++ 版引数 Rust 版 LazySegtree の対応
S MapMonoid::M::S の定義
op MapMonoid::M::binary_operation の定義
e MapMonoid::M::identity の定義
F MapMonoid::F の定義
mapping MapMonoid::mapping の定義
composition MapMonoid::composition の定義
id MapMonoid::identity_map の定義

LazySegtree を利用するためには、MapMonoid を満たす型を実装し、その中に Monoid を満たす型を含める必要があります。

<区間最小値, 区間加算> の LazySegtree の実装

まず、最も基本的な例として、区間最小値 (RMQ) に対する区間加算を行う LazySegtree を実装してみます。

use std::i64;
use ac_library::{LazySegtree, MapMonoid, Monoid};

struct U;

impl Monoid for U {
    type S = i64;
    fn identity() -> Self::S {
        i64::MAX
    }
    fn binary_operation(a: &Self::S, b: &Self::S) -> Self::S {
        *a.min(b)
    }
}

struct T;

impl MapMonoid for T {
    type M = U;
    type F = i64;
    fn identity_map() -> Self::F {
        0
    }
    fn mapping(f: &Self::F, x: &<Self::M as Monoid>::S) -> <Self::M as Monoid>::S {
        *f + *x
    }
    fn composition(f: &Self::F, g: &Self::F) -> Self::F {
        *f + *g
    }
}

fn main() {
    let mut ls = LazySegtree::<T>::new(10);
}

この実装では、

  • U で区間最小値のモノイドを定義 (i64::MAX を単位元として min を二項演算に採用)
  • TMapMonoid を定義し、作用素として区間加算を実装

という形になっています。

ac_libraryMin<T> を使った簡略化

ACL には Min<T> という便利な型が用意されており、上記の Monoid を簡単に定義できます。

use ac_library::{LazySegtree, MapMonoid, Min, Monoid};

struct T;

impl MapMonoid for T {
    type M = Min<i64>;
    type F = i64;
    fn identity_map() -> Self::F {
        0
    }
    fn mapping(f: &Self::F, x: &<Self::M as Monoid>::S) -> <Self::M as Monoid>::S {
        *f + *x
    }
    fn composition(f: &Self::F, g: &Self::F) -> Self::F {
        *f + *g
    }
}

この Min<i64> を用いると、Monoid の定義が不要になり、より簡潔な実装が可能になります。ただし、Min<T>Max<T> は Rust の組み込み整数型 (i64, i32 など) にしか対応していない(何らかのトレイトを満たせば使えるというわけではない。)ため、他の型 (多倍長整数など) を使いたい場合は前述の手動実装が必要になります。
Min<i64>の定義されているファイルにただのセグメントツリー用の Additive<T>(, Multiplicative<T>) が定義されていますが、そもそも<区間和, 区間更新>, <区間和, 区間加算> いずれも遅延伝播セグメントツリーでは要素数の情報の保持が必須なので使えません。

注意点として、ls.set(p, x) を繰り返してすべての要素を初期化してから他の機能を利用しないと、内部でf(>0) + i64::MAXが原因のオーバーフローを起こします。

<区間和, 区間更新> の LazySegtree の実装

次に、区間和 (RSQ) に対する区間更新を行う LazySegtree を実装します。

struct U;

impl Monoid for U {
    type S = (i64, i64); // (合計値, 要素数)
    fn identity() -> Self::S {
        (0, 1)
    }
    fn binary_operation(a: &Self::S, b: &Self::S) -> Self::S {
        (a.0 + b.0, a.1 + b.1)
    }
}

struct T;

impl MapMonoid for T {
    type M = U;
    type F = Option<i64>;
    fn identity_map() -> Self::F {
        None
    }
    fn mapping(f: &Self::F, x: &<Self::M as Monoid>::S) -> <Self::M as Monoid>::S {
        match *f {
            Some(v) => (v * x.1, x.1),
            None => *x,
        }
    }
    fn composition(f: &Self::F, g: &Self::F) -> Self::F {
        match *f {
            Some(_) => *f,
            None => *g,
        }
    }
}

この実装では、

  • U で区間和のモノイドを定義し、値と要素数をタプルで保持
  • TMapMonoid を定義し、作用素として区間更新 (Some(v) の場合は v * 要素数 を設定)

という形になっています。

まとめ

ACL の LazySegtree は、区間操作を効率的に処理できる強力なデータ構造です。Rust では ac_library を利用することで、C++ の LazySegtree に相当する機能を簡単に実装できます。

  • Monoid を定義し、identitybinary_operation を実装
  • MapMonoid を定義し、mappingcomposition を実装
  • ac_libraryMin<T>Max<T> を使うと簡略化可能

実際の競技プログラミングで活用する際は、用途に応じて適切な MonoidMapMonoid を設計するとよいでしょう。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?