注意:以下代码均在加入如下代码的情况下运行:
#include<bits/stdc++.h>
using namespace std;
有些东西我写了,没测试过,可能有bug。大概率保证说明中的函数没有bug。
模板1:单点修改(不带懒标记)
使用说明
模板参数:typename S,int N
SegTree<S,N>是以S为元素类型,以求和为操作,以S()为默认元素,长度最大为N的线段树
要求实现S的默认构造函数,S的加法仍然能得到S且满足交换律
即对于任何x,y,z属于S,x+y属于S且(x+y)+z=x+(y+z)
void reset(int x=N,vec.tor<S> v={})
建树,长度为x,初始元素为v。若v.size()不等于x(默认不等),初始元素全都为默认元素。O(n)个加运算
const int&size() const
返回建树时的长度x,O(1)
void modify(int p,const S&v)
修改第p个元素为v。O(lgn)个加运算
S query(int a,int b) const
求[a,b)的和。O(lgn)个加运算
const S& all_query()const
返回[0,长度)的和。O(1)
const S& get(int p)const
求第p个元素。O(lgn)
int max_right<class Ch>(int l,const Ch&judge)
线段树上二分,返回一个r使得[l,r)输入judge返回true,而[l,r]输入judge返回false。O(lgn)个加运算与judge函数
范例
求范围内的和,最小值,最大值。(输入位置在[1,n]的闭区间)
const int N=5e5+100;
int n,m,a[N];
char op;int x,y;
struct Data {
int sum,mini,maxi;
Data(): sum(0),mini(1e9),maxi(-1e9) {}
Data(int val): sum(val),mini(val),maxi(val) {}
Data(int _s,int _min,int _max): sum(_s),mini(_min),maxi(_max) {}
Data operator+(const Data& b) const {
return Data(sum+b.sum,min(mini,b.mini),max(maxi,b.maxi));
}
void print() const {cout<<sum<<' '<<mini<<' '<<maxi<<endl;}
};
SegTree<Data,N> seg;
signed main() {
cin>>n>>m;
for(int i=0;i<n;i++) cin>>a[i];
seg.reset(n,vector<Data>(a,a+n));
while(m--) {
cin>>op>>x>>y;
if(op=='C') seg.modify(x-1,y);
else if(op=='Q') seg.query(x-1,y).print();
}
return 0;
}
代码
namespace segtree {
template<typename S,int N>
class SegTree {
static_assert(is_convertible<decltype(S()+S()),S>::value,"cannot get S from addition");
private:
struct Data {
int l,r;
S d;
int lf,rf;
int length()const{return r-l;}
bool isLeaf()const{return length()==1;}
int mid()const{return (l+r)>>1;}
};
Data d[N*2];
int cnt;
void calc(int x) {d[x].d=d[x].lf[d].d+d[x].rf[d].d;}
void build(int x,int l,int r,const vector<S>& v) {
d[x].l=l;d[x].r=r;
if(d[x].isLeaf()) d[x].d=v[d[x].l];
else {
build(d[x].lf=++cnt,l,d[x].mid(),v);
build(d[x].rf=++cnt,d[x].mid(),r,v);
calc(x);
}
}
void modify(int x,int p,const S&v) {
if(d[x].isLeaf()) {d[x].d=v;return;}
if(p<d[x].mid()) modify(d[x].lf,p,v);
else modify(d[x].rf,p,v);
calc(x);
}
const S&get(int x,int p) const {
if(d[x].isLeaf()) return d[x].d;
if(p<d[x].mid()) return get(d[x].lf,p);
else return get(d[x].rf,p);
}
S query(int x,int a,int b)const{
if(a<=d[x].l&&d[x].r<=b) return d[x].d;
if(a<d[x].mid()) {
S s=query(d[x].lf,a,b);
if(b>d[x].mid()) return s+query(d[x].rf,a,b);
return s;
}
return query(d[x].rf,a,b);
}
template<class Check>
int _max_right(int x,S&val,int l,const Check&check) {
if(l<=d[x].l) {
S nv=val+d[x].d;
if(check(nv)) {val=nv;return -1;}
if(d[x].isLeaf()) return d[x].l;
}
int pos=-1;
if(l<d[x].mid()) pos=_max_right(d[x].lf,val,l,check);
if(pos!=-1) return pos;
return _max_right(d[x].rf,val,l,check);
}
public:
void reset(int x=N,vector<S> v={}) {
if(v.size()!=x) v.assign(x,S());
cnt=1;build(1,0,x,v);
}
const int&size() const {return d[1].r;}
void modify(int p,const S&v) {modify(1,p,v);}
S query(int a,int b) const {return query(1,a,b);}
const S& all_query()const{return d[1].d;}
const S& get(int p)const{return get(1,p);}
template<class Check>
int max_right(int l,const Check&check) {
S val=this->get(l);
if(!check(val)) return l;
++l;if(l==size()) return l;
int pos=_max_right<Check>(1,val,l,check);
return pos;
}
template<bool(*check)(S)>int max_right(int l)
{return max_right(l,[](const S&s){return check(s);});}
};
}
using segtree::SegTree;
模板2:区间修改(带懒标记)
使用说明
模板参数:typename S,class F,int N
LazySegTree<S,F,N>是以S为元素类型,以求和为操作,以S()为默认元素,以F为操作类型,以乘上元素为操作,以F()为幺元,长度最大为N的线段树
要求:
- 实现S的默认构造函数
- S的加法仍然能得到S
- S的加法满足交换律
- F对S的乘法能得到S
- F的乘法能得到F
- F的默认构造函数返回幺元,因此F一定要自定义结构体(用以下编写好的也可以)
- F对S的乘法对S的加法有分配律,即
- F与F与S的乘法有结合律,即
- F的乘法有结合律
以下时间复杂度中常数次“下传”操作指常数次F*F与常数次F*S
void reset(int x=N,ve.ctor<S> v={})
建树,长度为x,初始元素为v。若v.size()不等于x(默认不等),初始元素全都为默认元素。O(n)个S加法
const int&size() const
返回建树时的长度x,O(1)
void modify(int p,const S&v)
修改第p个元素为v。O(lgn)个S加法,O(lgn)个下传
void apply(int p,const F&f)
把操作f应用到第p个元素。O(lgn)个S加法,O(lgn)个下传
S query(int a,int b)
求[a,b)的和。O(lgn)个S加法,O(lgn)个下传
const S& all_query()const
返回[0,长度)的和。O(1)
const S& get(int p)
求第p个元素。O(lgn)个下传
int max_right<class Ch>(int l,const Ch&judge)
线段树上二分,返回一个r使得[l,r)输入judge返回true,而[l,r]输入judge返回false。O(lgn)个S加法,O(lgn)次judge函数,O(lgn)个下传
范例
以下代码是对区间元素进行加或乘操作,输出区间和
typedef long long ll;
int p=100;
struct Data {
int l,s;
Data(int v=114514): l(1),s(v) {}
Data(int len,ll sum): l(len),s(sum%p) {}
};
Data operator+(Data a,Data b){return Data(a.l+b.l,a.s+b.s);}
struct Change {
int m,a;
Change(ll mul=1,ll add=0): m(mul%p),a(add%p) {}
Data operator*(Data d)const{return Data(d.l,d.s*1ll*m+d.l*1ll*a);}
};
Change operator*(Change a,Change b){return Change(a.m*1ll*b.m,b.a*1ll*a.m+a.a);}// apply a on b
const int N=100000+100;
int n,m,a[N];
LazySegTree<Data,Change,N> seg;
int op,t,g,c;
signed main() {
cin>>n>>p;
for(int i=1;i<=n;i++) cin>>a[i];
seg.reset(n+10,vector<Data>(a,a+n+10));
cin>>m;
while(m--) {
cin>>op>>t>>g;g++;
if(op==1) {
cin>>c;
seg.apply(t,g,Change(c,0));
}else if(op==2) {
cin>>c;
seg.apply(t,g,Change(1,c));
}else if(op==3) {
cout<<seg.query(t,g).s<<endl;
}
}
return 0;
}
代码
由于代码行数巨大,可以删去不用的。
namespace segtree {
template<typename S,class F,int N>
class LazySegTree {
static_assert(is_convertible<decltype(S()+S()),S>::value,"cannot combine S");
static_assert(is_convertible<decltype(F()*S()),S>::value,"cannot apply on S");
static_assert(is_convertible<decltype(F()*F()),F>::value,"cannot apply on F");
public:
struct Data {
int l,r;
S d;F f;
int lf,rf;
int length(){return r-l;}
bool isLeaf(){return length()==1;}
int mid(){return (l+r)>>1;}
void operator*=(const F&ff) {d=ff*d;f=ff*f;}
};
Data d[N*2];
int cnt;
void _pushUp(int x) {d[x].d=d[x].lf[d].d+d[x].rf[d].d;}
void _pushDown(int x) {
if(!d[x].isLeaf()) {
d[x].lf[d]*=d[x].f;
d[x].rf[d]*=d[x].f;
}
d[x].f=F();
}
void _build(int x,int l,int r,const vector<S>& v) {
d[x].l=l;d[x].r=r;d[x].f=F();
if(d[x].isLeaf()) {
d[x].d=v[l];
}
else {
_build(d[x].lf=++cnt,l,d[x].mid(),v);
_build(d[x].rf=++cnt,d[x].mid(),r,v);
_pushUp(x);
}
}
void _modify(int x,int p,const S&v) {
if(d[x].isLeaf()) {d[x].d=v;return;}
_pushDown(x);
if(p<d[x].mid()) _modify(d[x].lf,p,v);
else _modify(d[x].rf,p,v);
_pushUp(x);
}
void _apply(int x,int p,const F&f) {
if(d[x].isLeaf()) {d[x].d=f*d[x].d;return;}
_pushDown(x);
if(p<d[x].mid()) _apply(d[x].lf,p,f);
else _apply(d[x].rf,p,f);
_pushUp(x);
}
const S&_get(int x,int p) {
if(d[x].isLeaf()) return d[x].d;
_pushDown(x);
return _get(p<d[x].mid()?d[x].lf:d[x].rf,p);
}
S _get(int x,int p)const {
if(d[x].isLeaf()) return d[x].d;
S ans=_get(p<d[x].mid()?d[x].lf:d[x].rf,p);
return d[x].f*ans;
}
S _query(int x,int a,int b) {
if(a<=d[x].l&&d[x].r<=b) return d[x].d;
_pushDown(x);
if(a<d[x].mid()) {
S s=_query(d[x].lf,a,b);
if(b>d[x].mid()) return s+_query(d[x].rf,a,b);
return s;
}
return _query(d[x].rf,a,b);
}
S _query(int x,int a,int b)const{
if(a<=d[x].l&&d[x].r<=b) return d[x].d;
if(a<d[x].mid()) {
S s=d[x].f*_query(d[x].lf,a,b);
if(b>d[x].mid()) return s+d[x].f*_query(d[x].rf,a,b);
return s;
}
return d[x].f*_query(d[x].rf,a,b);
}
void _apply(int x,int a,int b,const F&f) {
if(a<=d[x].l&&d[x].r<=b) {d[x]*=f;return;}
_pushDown(x);
if(a<d[x].mid()) _apply(d[x].lf,a,b,f);
if(b>d[x].mid()) _apply(d[x].rf,a,b,f);
_pushUp(x);
}
template<class Check>
int _max_right(int x,S&val,int l,const Check&check) {
_pushDown(x);
if(l<=d[x].l) {
S nv=val+d[x].d;
if(check(nv)) {val=nv;return -1;}
if(d[x].isLeaf()) return d[x].l;
}
int pos=-1;
if(l<d[x].mid()) pos=_max_right(d[x].lf,val,l,check);
if(pos!=-1) return pos;
return _max_right(d[x].rf,val,l,check);
}
public:
void reset(int x=N,vector<S> v={}) {
if(v.size()!=x) v.assign(x,S());
cnt=1;_build(1,0,x,v);
}
const int&size()const{return d[1].r;}
void modify(int p,const S&v) {_modify(1,p,v);}
void apply(int p,const F&f) {_apply(1,p,f);}
void apply(int l,int r,const F&f) {if(l<r)_apply(1,l,r,f);}
S query(int a,int b) {return _query(1,a,b);}
S query(int a,int b)const{return _query(1,a,b);}
const S& all_query() const {return d[1].d;}
const S& get(int p){return _get(1,p);}
S get(int p)const{return _get(1,p);}
template<class Check>
int max_right(int l,const Check&check) {
S val=this->get(l);
if(!check(val)) return l;
++l;if(l==size()) return l;
int pos=_max_right<Check>(1,val,l,check);
return pos;
}
template<bool(*check)(S)>int max_right(int l)
{return max_right(l,[](const S&s){return check(s);});}
};
}
using segtree::LazySegTree;
其他:各种S与F
由于每次都编写同样的S与F太麻烦,我整理了一些。
data:可用于S
MinMax<typename T>
存储最大最小值。默认构造函数返回幺元(此时valid()返回false)。不用幺元正常使用的话valid()返回true。
当前联动F:MulAdd<T>
MaxSubSum<typename T>
存储最大子段和(顺便存储最大前缀和,最大后缀和,总和)。如果T的默认构造函数返回幺元,那么MaxSubSum<T>的默认构造函数也返回幺元。
change:可用于F
MulAdd<typename T>
把值先乘后加。要求1转为T是乘法幺元,0转为T是加法幺元,才能使得默认构造函数返回幺元。要求分配律,结合律。
当前联动S:T,MinMax<T>(要求乘负数不等号方向改变),等(用类似*T的方法)
代码
namespace segtree {
namespace data {
template<typename T>
struct MinMax {
T minv,maxv;
MinMax():minv(numeric_limits<T>::max()),maxv(numeric_limits<T>::min()){}
MinMax(const T&v):minv(v),maxv(v) {}
MinMax(const T&_min,const T&_max):minv(_min),maxv(_max) {}
bool valid(){return minv<=maxv;}
};
template<typename T>MinMax<T> operator+(const MinMax<T>&a,const MinMax<T>&b)
{return MinMax<T>(min(a.minv,b.minv),max(a.maxv,b.maxv));}
template<typename T>
struct MaxSubSum {
T lans,rans,ans,sum;
MaxSubSum(const T&v=T()): lans(v),rans(v),ans(v),sum(v) {}
MaxSubSum(const T&l,const T&r,const T&a,const T&s):
lans(l),rans(r),ans(a),sum(s) {}
};
template<typename T>MaxSubSum<T>operator+(const MaxSubSum<T>&l,const MaxSubSum<T>&r) {
return MaxSubSum<T>(max(l.lans,l.sum+r.lans),
max(r.rans,r.sum+l.rans),
max({l.ans,r.ans,l.rans+r.lans}),
l.sum+r.sum);
}
}
namespace change {
template<typename T>
struct MulAdd {
T m,a;
MulAdd(): MulAdd(1,0) {}
MulAdd(const T&mul,const T&add):m(mul),a(add){}
T operator*(const T&v)const{return m*v+a;}
template<typename V>auto operator*(const V&v)const{return m*v+a;}
};
template<typename T>MulAdd<T>operator*(const MulAdd<T>&snd,const MulAdd<T>&fst)
{return MulAdd<T>(snd.m*fst.m,snd*fst.a);}
template<typename T>
struct Addition {
T val;
Addition():val(T()) {}
Addition(const T&v):val(v) {}
T operator*(const T&v)const{return val+v;}
template<typename V>auto operator*(const V&v)const{return val+v;}
};
template<typename T>Addition<T>operator*
(const Addition<T>&snd,const Addition<T>&fst){return snd*fst.val;}
}
template<typename T>data::MinMax<T>operator*(const change::MulAdd<T>&f,const data::MinMax<T>&v)
{T minv=f*v.minv;T maxv=f*v.maxv;if(f.m<0)return data::MinMax<T>(maxv,minv);return data::MinMax<T>(minv,maxv);}
}