acwing 1277
地址: 传送门
输入样例:
7 43
1 2 3 4 5 6 7
5
1 2 5 5
3 2 4
2 3 7 9
3 1 3
3 4 7
输出样例:
2
35
8
思路:这道题有两种区间修改,一种是加法,另一种是乘法。
所以就要设两个懒标记,一个是add,另一个是mul ,对于这两种操作,就有了优先级的问题。
如果我们对于懒标记先加再乘,譬如 (t * a) + b ,这种情况下,若在其整体再进行乘法,pushdown就很难维护出来。 因为懒标记要满足一个性质叫可叠加性,就是说可以通过上面的来算出下面两个儿子的值,也可以反推回去。 先加后乘是行不通的。
然后再想,是否可以对于懒标记先乘再加,同样是 (t * a) + b ,
若对其整体加一个数字k 则可以将 b + k 看成一个整体。
若对其整体乘一个数字k, 则该式变成 t * a * k + b * k ,可以看成 t * (a * k) + (b * k)
这样就可以很方便的把父节点懒标记传递给子节点。
我们可以把这两种操作合并在一起,写成一个函数, 即 如果是光加一个数,那么相当于 t * 0 + k
如果是乘法,相当于 t * k + 0
具体细节看代码:
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
typedef long long ll;
const int N = 100010;
int n,m,p;
int w[N];
struct node{
int l,r;
int sum,add,mul;
}tr[N<<2];
void pushup(int u){
tr[u].sum =( tr[u<<1].sum + tr[u<<1|1].sum ) % p;
}
void oper(node &t,int add,int mul){
/*
1. 对于懒标记,如果在pushdown中修改非懒标记,就要统计当前结点上的懒标记,并带入运算
如果修改的是懒标记,意思是将懒标记传给左右儿子,自身再清空
*/
t.sum = ((ll)t.sum*mul + (ll)(t.r-t.l+1)*add ) % p;
t.mul = (ll)t.mul*mul%p;
t.add = ((ll)t.add*mul + add)%p;
}
void pushdown(int u){
oper(tr[u<<1],tr[u].add,tr[u].mul);
oper(tr[u<<1|1],tr[u].add,tr[u].mul);
tr[u].add = 0;
tr[u].mul = 1;
}
void build(int u,int l,int r){
if(l == r) tr[u] = {l,r,w[r],0,1};
else{
tr[u] = {l,r,0,0,1};
int mid =l+r >> 1;
build(u<<1,l,mid);
build(u<<1|1,mid+1,r);
pushup(u);
}
}
void modify(int u,int l,int r,int add,int mul){
if(tr[u].l>=l && tr[u].r<=r) oper(tr[u],add,mul);
else{
pushdown(u);
int mid = tr[u].l + tr[u].r >> 1;
if(l<=mid) modify(u<<1,l,r,add,mul);
if(r>mid) modify(u<<1|1,l,r,add,mul);
pushup(u);
}
}
int query(int u,int l,int r){
if(tr[u].l>=l && tr[u].r <= r) return tr[u].sum;
pushdown(u);
int mid = tr[u].l + tr[u].r >> 1;
int ans = 0;
if(l<=mid) ans = query(u<<1,l,r);
if(r>mid) ans = (ans+query(u<<1|1,l,r))%p;
return ans;
}
int main(){
cin>>n>>p;
for(int i=1;i<=n;i++) cin>>w[i];
build(1,1,n);
cin>>m;
while(m--){
int op,t,g;
cin>>op>>t>>g;
if(op == 1){
int c; cin>>c;
modify(1,t,g,0,c);
}
else if(op == 2){
int c; cin>>c;
modify(1,t,g,c,1);
} else{
cout<<query(1,t,g)%p<<endl;
}
}
return 0;
}