Info

Monoidの区間fold、区間更新が\(O(\log{n})\)でできるデータ構造

Complexity

構築 - \(O(n)\)
区間更新 - \(O(\log{n})\)
区間fold - \(O(\log{n})\)

Interface

LazySegmentTree<M,OM>(int n) モノイド\(M\)、作用素\(OM\)、大きさ\(n\)で初期化する
[i] \(i\)番目の要素への参照を返す(最初のbuild()の前に事前に初期化するときに使う)
build() セグ木を構築する(すべての要素が単位元で初期化の場合も使う)
update(int l,int r,OM a) \([l,r)\)の区間に作用素\(a\)を適用する
fold(int l,int r) 区間\([l,r)\)をfoldした値を返す

Interface(Monoid)

I() 単位元を返す
f(M lhs, M rhs) モノイド間の演算\(f:(M,M)\rightarrow M\)

Interface(Operator Monoid)

I() 単位元を返す
g(M m, OM om) モノイドに作用素を適用するときの演算\(g:(M,OM)\rightarrow M\)
h(OM first, OM second) 作用素間の演算\(h:(OM,OM)\rightarrow OM\)

Code

using lnt=long long;
/* <LazySegmentTree> */

template<typename M, typename OM>
struct LazySegmentTree
{
	int n,h;
	std::vector<M> data; std::vector<OM> lazy;
	LazySegmentTree(int N) : n(1),h(0) { while(n<N) n<<=1,h++; data.assign(n<<1,M::I()); lazy.assign(n,OM::I()); }
	M& operator[](int i) { return data[i+n]; } // unsafe. use only with build()
	void build() { for(int i=n-1;i>0;i--) data[i]=M::f(data[i<<1],data[i<<1|1]); } // build() even when all I
	void apply(int i, const OM& o) { if(i<n) lazy[i]=OM::h(lazy[i],o); data[i]=OM::g(data[i],o); }
	void propagate(int i) { if(lazy[i].alive) { apply(i<<1,lazy[i]); apply(i<<1|1,lazy[i]); lazy[i]=OM::I(); } }
	void thrust(int i) { for(int j=h;j>0;j--) propagate(i>>j); }
	void recalc(int i) { for(;i>1;i>>=1) data[i>>1]=M::f(data[i],data[i^1]); }
	void update(int l, int r, const OM& o) {
		l+=n;r+=n; int l0=l/(l&-l),r0=r/(r&-r); thrust(l0); thrust(r0-1);
		for(;l<r;l>>=1,r>>=1) { if(l&1) apply(l++,o); if(r&1) apply(--r,o); }
		recalc(l0); recalc(r0-1);
	}
	M fold(int l, int r) {
		l+=n;r+=n; int l0=l/(l&-l),r0=r/(r&-r); thrust(l0); thrust(r0-1); recalc(l0); recalc(r0-1);
		M L=M::I(),R=M::I(); for(;l<r;l>>=1,r>>=1) { if(l&1) L=M::f(L,data[l++]); if(r&1) R=M::f(data[--r],R); }
		return M::f(L,R);
	}
	M get(int i) { return fold(i,i+1); }
};

/* <LazySegmentTree> */

/* <LazySegmentTree::RangeAffineRangeSum> */
template<typename T=lnt>
struct RangeAffineRangeSum
{
	struct M
	{
		T v; int n;
		static M I() { return M(0,1); }
		M(T v, int n=1) : v(v),n(n) {}
		static M f(const M& lhs, const M& rhs) { return M(lhs.v+rhs.v,lhs.n+rhs.n); }
		operator T() const { return v; }
	};

	struct OM
	{
		T a, b; bool alive;
		static OM I() { return OM(); }
		OM() : alive(false) {}
		OM(T a, T b) : a(a),b(b),alive(true) {}
		static M g(const M& m, const OM& om) { if(om.alive) return M(m.v*om.a+T(m.n)*om.b,m.n); else return m; }
		static OM h(const OM& first, const OM& second) {
			if(first.alive&&second.alive) return OM(first.a*second.a, first.b*second.a+second.b);
			return (first.alive)?first:second;
		}
	};
};
/* <LazySegmentTree::RangeAffineRangeSum> */

/* <LazySegmentTree::RangeAffineRangeMinMax> */
// untested
template<typename T=lnt>
struct RangeAffineRangeMinMax
{
	struct M
	{
		struct V
		{
			T v; int i;
			operator T() const { return v; } 
			V(T v, int i=-1) : v(v),i(i) {}
		};
		V min, max;
		static M I() { return M(std::numeric_limits<T>::max(),std::numeric_limits<T>::min()); }
		M(T v, int i=-1) : min(v,i),max(v,i) {}
		M(V min,V max) : min(min),max(max) {}
		static M f(const M& lhs, const M& rhs) {
			return M((lhs.min.v<rhs.min.v)?lhs.min:rhs.min, (rhs.max.v<lhs.max.v)?lhs.max:rhs.max);
		}
	};

	struct OM
	{
		T a, b; bool alive;
		static OM I() { return OM(); }
		OM() : alive(false) {}
		OM(T a, T b) : a(a),b(b),alive(true) {}
		static M g(M m, const OM& om) {
			if(om.alive) {
				if(om.a<0) std::swap(m.min,m.max);
				m.min.v*=om.a; m.min.v+=om.b;
				m.max.v*=om.a; m.max.v+=om.b;
				return m;
			} else return m;
		}
		static OM h(const OM& first, const OM& second) {
			if(first.alive&&second.alive) return OM(first.a*second.a, first.b*second.a+second.b);
			return (first.alive)?first:second;
		}
	};
};
/* <LazySegmentTree::RangeAffineRangeMinMax> */

Examples

using T=RangeAffineRangeSum<int>;
LazySegmentTree<T::M,T::OM> seg(10);

for(int i=0;i<10;i++) seg[i]=i;
seg.build();

std::cout << seg.fold(2,5) << '\n'; // 9

seg.update(2,4,T::OM(100,-50)); // x=x*100+(-50)

std::cout << seg.fold(2,5) << '\n'; // 404