一道区间更新的线段树的题,但是这里有需要注意的地方就是关于“乘积”与“和”的关系处理,如果改变他们的顺序就会造成最后的答案WA,所以我们每次输入就要去更新数据的同时,更新Lazy标记,而Lazy标记又分为set与add,其中set表示乘积,add表示和的形式,每次输入的时候,我们就要对访问到的节点向下更新,不仅是对节点值的更新,还有Lazy标记的值也需要实时更新。
题目链接
#include <iostream>
#include <cstdio>
#include <cmath>
#include <string>
#include <cstring>
#include <algorithm>
#include <limits>
#include <vector>
#include <stack>
#include <queue>
#include <set>
#include <map>
#define lowbit(x) ( x&(-x) )
#define pi 3.141592653589793
#define e 2.718281828459045
using namespace std;
typedef long long ll;
const int maxN=1e5+7;
int N,M;
ll P; //P为取余的
ll trie[maxN<<2];
ll a[maxN];
ll lazy_set[maxN<<2];
ll lazy_add[maxN<<2];
inline void buildTree(int rt, int l, int r)
{
if(l==r)
{
trie[rt]=a[l]%P;
return;
}
int mid=(l+r)>>1;
buildTree(rt<<1, l, mid);
buildTree(rt<<1|1, mid+1, r);
trie[rt]=( trie[rt<<1]+trie[rt<<1|1] )%P;
}
void pushdown(int rt, int l, int r)
{
int mid=(l+r)>>1;
if(lazy_set[rt]==1 && lazy_add[rt]==0) return;
lazy_set[rt<<1]=lazy_set[rt<<1]*lazy_set[rt]%P;
lazy_add[rt<<1]=(lazy_add[rt<<1]*lazy_set[rt]%P+lazy_add[rt])%P;
trie[rt<<1]=(trie[rt<<1]*lazy_set[rt]%P+lazy_add[rt]*(mid-l+1)%P)%P;
lazy_set[rt<<1|1]=lazy_set[rt<<1|1]*lazy_set[rt]%P;
lazy_add[rt<<1|1]=(lazy_add[rt<<1|1]*lazy_set[rt]%P+lazy_add[rt])%P;
trie[rt<<1|1]=(trie[rt<<1|1]*lazy_set[rt]%P+lazy_add[rt]*(r-mid)%P)%P;
lazy_set[rt]=1;
lazy_add[rt]=0;
}
inline void update(int rt, int l, int r, int ql, int qr, int qs, ll q) //qs指询问是‘1’还是‘2’
{
if(ql<=l && qr>=r)
{
if(qs==1) //乘积的形式
{
lazy_set[rt]=(lazy_set[rt]*q)%P;
lazy_add[rt]=lazy_add[rt]*q%P;
trie[rt]=trie[rt]*q%P;
}
else //和的形式
{
lazy_add[rt]=(lazy_add[rt]+q)%P;
trie[rt]=(trie[rt]+q*(r-l+1))%P;
}
return;
}
pushdown(rt, l, r);
int mid=(l+r)>>1;
if(ql<=mid) update(rt<<1, l, mid, ql, qr, qs, q);
if(qr>mid) update(rt<<1|1, mid+1, r, ql, qr, qs, q);
trie[rt]=(trie[rt<<1]+trie[rt<<1|1])%P;
}
ll Query(int rt, int l, int r, int ql, int qr)
{
if(ql<=l && qr>=r) return trie[rt]%P;
pushdown(rt, l, r);
int mid=(l+r)>>1;
ll ans=0;
if(ql<=mid) ans=(ans+Query(rt<<1, l, mid, ql, qr))%P;
if(qr>mid) ans=(ans+Query(rt<<1|1, mid+1, r, ql, qr))%P;
return ans;
}
int main()
{
while(scanf("%d %lld",&N,&P)!=EOF)
{
memset(trie, 0, sizeof(trie));
memset(a, 0, sizeof(a));
memset(lazy_add, 0, sizeof(lazy_add));
fill(lazy_set, lazy_set+(maxN<<2), 1);
for(int i=1; i<=N; i++)
{
scanf("%lld",&a[i]);
a[i]%=P;
}
buildTree(1, 1, N);
scanf("%d",&M);
for(int i=0; i<M; i++)
{
int e1,e2,e3;
ll e4;
scanf("%d",&e1);
if(e1==1 || e1==2)
{
scanf("%d%d%lld",&e2,&e3,&e4);
update(1, 1, N, e2, e3, e1, e4);
}
else
{
scanf("%d%d",&e2,&e3);
printf("%lld\n",Query(1, 1, N, e2, e3)%P);
}
}
}
return 0;
}