一个带区间修改的线段树求和模板:
int MAXN = 100005; ll a[100005<<2],ans,p; struct Tree { ll l,r; ll sum,add,mul; } tree[100005<<2]; void pushdown(int tr,int len) { if(len==1) return; long long m=tree[tr].mul,a=tree[tr].add; tree[tr*2].sum=(tree[tr*2].sum*m%p+(len-(len>>1))*a%p)%p; tree[tr*2+1].sum=(tree[tr*2+1].sum*m%p+(len>>1)*a%p)%p; tree[tr*2].add=(tree[tr*2].add*m%p+a)%p; tree[tr*2+1].add=(tree[tr*2+1].add*m%p+a)%p; tree[tr*2].mul=tree[tr*2].mul*m%p; tree[tr*2+1].mul=tree[tr*2+1].mul*m%p; tree[tr].mul=1; tree[tr].add=0; } void pushup(ll x) { ll tmp=2*x; tree[x].sum=(tree[tmp].sum+tree[tmp+1].sum)%p; } void build(int l,int r,int x) { tree[x].l=l; tree[x].r=r; tree[x].add=0; tree[x].mul = 1; if(l==r) { tree[x].sum = a[l]; return ; } int tmp=x<<1; int mid=(l+r)>>1; build(l,mid,tmp); build(mid+1,r,tmp+1); pushup(x); } void update(ll l,ll r,ll c1,ll c2,ll x) { //c1代表乘法 c2代表加法 pushdown(x,tree[x].r-tree[x].l+1); if(r<tree[x].l||l>tree[x].r) return ; if(l<=tree[x].l&&r>=tree[x].r) { tree[x].sum=(tree[x].sum*c1%p+c2*(tree[x].r-tree[x].l+1))%p; tree[x].mul=c1*tree[x].mul%p; tree[x].add=(tree[x].add*c1%p+c2)%p; return ; } ll tmp=x<<1; update(l,r,c1,c2,tmp); update(l,r,c1,c2,tmp+1); pushup(x); } void query(ll l,ll r,ll x) { if(r<tree[x].l||l>tree[x].r) return ; if(l<=tree[x].l&&r>=tree[x].r) { ans+=tree[x].sum; return ; } pushdown(x,tree[x].r-tree[x].l+1); ll tmp=x<<1; ll mid=(tree[x].l+tree[x].r)>>1; if(r<=mid) query(l,r,tmp); else if(l>mid) query(l,r,tmp+1); else { query(l,mid,tmp); query(mid+1,r,tmp+1); } }