#pragma once
template<typenameLazy>classLazySegmentTree{usingMX=typenameLazy::MX;usingMF=typenameLazy::MF;usingX=typenameMX::value_type;usingF=typenameMF::value_type;intn,log,size;std::vector<X>dat;std::vector<F>laz;Xreflect(intk){if(k<size)returnLazy::mapping(laz[k],dat[k]);returndat[k];}voidpoint_apply(intk,constF&f){if(k<size)MF::Lchop(f,laz[k]);elsedat[k]=Lazy::mapping(f,dat[k]);}voidpush(intk){dat[k]=reflect(k);point_apply(2*k,laz[k]);point_apply(2*k+1,laz[k]);laz[k]=MF::unit();}voidthrust(intk){for(inti=log;i;i--)push(k>>i);}voidupdate(inti){dat[i]=MX::op(reflect(2*i),reflect(2*i+1));}voidrecalc(intk){while(k>>=1)update(k);}public:LazySegmentTree():LazySegmentTree(0){}LazySegmentTree(intn):LazySegmentTree(std::vector<X>(n,MX::unit())){}LazySegmentTree(conststd::vector<X>&v):n(v.size()){for(log=1;(1<<log)<n;log++){}size=1<<log;dat.assign(size<<1,MX::unit());laz.assign(size,MF::unit());for(inti=0;i<n;++i)dat[size+i]=v[i];for(inti=size-1;i>=1;--i)update(i);}voidset(intp,Xx){assert(0<=pandp<n);thrust(p+=size);dat[p]=x;recalc(p);}Xoperator[](intp){assert(0<=pandp<n);thrust(p+=size);returnreflect(p);}Xprod(intL,intR){assert(0<=LandL<=RandR<=n);if(L==R)returnMX::unit();thrust(L+=size);thrust((R+=size-1)++);Xvl=MX::unit(),vr=MX::unit();while(L<R){if(L&1)MX::Rchop(vl,reflect(L++));if(R&1)MX::Lchop(reflect(--R),vr);L>>=1,R>>=1;}returnMX::op(vl,vr);}voidapply(intl,intr,Ff){assert(0<=l&&l<=r&&r<=n);if(l==r)return;thrust(l+=size);thrust(r+=size-1);for(intL=l,R=r+1;L<R;L>>=1,R>>=1){if(L&1)point_apply(L++,f);if(R&1)point_apply(--R,f);}recalc(l);recalc(r);}};