This is a relatively simple line segment tree template question.
It is more to give an idea , the sequence problem when maintaining multiple operations that require Lazy Tag
For addition and query here, you can refer to interval addition template questions and Sol
Mainly when the mark is downloaded, pay attention to processing the multiplication first and then processing the addition
Why?
Because obviously multiplication has a higher priority than addition, if you add first and then multiply, it will explode
For example: 10+6*233
If the addition is calculated first, then it is 16*233, then it is obviously wrong
And even if this is the case such as (10+100)*233
You can also pass the multiplication mark to the addition first to become 10*233+100*233 ( the principle of the distributive law of multiplication , elementary school mathematics)
Then, after specifying the order, you can directly set the board of the line segment tree.
CODE
#include<cstdio>
using namespace std;
typedef long long LL;
const LL N=100005;
struct segtree
{
LL sum,add,mul;
}tree[N<<2];
LL n,m,p,a[N],opt,x,y,z;
inline char tc(void)
{
static char fl[100000],*A=fl,*B=fl;
return A==B&&(B=(A=fl)+fread(fl,1,100000,stdin),A==B)?EOF:*A++;
}
inline void read(LL &x)
{
x=0; char ch=tc();
while (ch<'0'||ch>'9') ch=tc();
while (ch>='0'&&ch<='9') x=x*10+ch-'0',ch=tc();
}
inline void write(LL x)
{
if (x/10) write(x/10);
putchar(x%10+'0');
}
inline void up(LL root)
{
tree[root].sum=(tree[root<<1].sum+tree[root<<1|1].sum)%p;
}
inline void down(LL root,LL l,LL r)
{
if (tree[root].add||tree[root].mul!=1)
{
tree[root<<1].mul=(tree[root<<1].mul*tree[root].mul)%p;
tree[root<<1|1].mul=(tree[root<<1|1].mul*tree[root].mul)%p;
tree[root<<1].add=(tree[root<<1].add*tree[root].mul)%p;
tree[root<<1|1].add=(tree[root<<1|1].add*tree[root].mul)%p;
tree[root<<1].sum=(tree[root<<1].sum*tree[root].mul)%p;
tree[root<<1|1].sum=(tree[root<<1|1].sum*tree[root].mul)%p;
tree[root].mul=1;
tree[root<<1].add=(tree[root<<1].add+tree[root].add)%p;
tree[root<<1|1].add=(tree[root<<1|1].add+tree[root].add)%p;
tree[root<<1].sum=(tree[root<<1].sum+tree[root].add*l)%p;
tree[root<<1|1].sum=(tree[root<<1|1].sum+tree[root].add*r)%p;
tree[root].add=0;
}
}
inline void build(LL root,LL l,LL r)
{
tree[root].mul=1;
if (l==r)
{
tree[root].sum=a[l];
return;
}
LL mid=l+r>>1;
build(root<<1,l,mid); build(root<<1|1,mid+1,r);
up(root);
}
inline void modify_mul(LL root,LL l,LL r,LL beg,LL end,LL k)
{
if (l>=beg&&r<=end)
{
tree[root].mul=(tree[root].mul*k)%p;
tree[root].add=(tree[root].add*k)%p;
tree[root].sum=(tree[root].sum*k)%p;
return;
}
LL mid=l+r>>1;
down(root,mid-l+1,r-mid);
if (beg<=mid) modify_mul(root<<1,l,mid,beg,end,k);
if (mid<end) modify_mul(root<<1|1,mid+1,r,beg,end,k);
up(root);
}
inline void modify_add(LL root,LL l,LL r,LL beg,LL end,LL k)
{
if (l>=beg&&r<=end)
{
tree[root].add=(tree[root].add+k)%p;
tree[root].sum=(tree[root].sum+k*(r-l+1))%p;
return;
}
LL mid=l+r>>1;
down(root,mid-l+1,r-mid);
if (beg<=mid) modify_add(root<<1,l,mid,beg,end,k);
if (mid<end) modify_add(root<<1|1,mid+1,r,beg,end,k);
up(root);
}
inline LL query(LL root,LL l,LL r,LL beg,LL end)
{
if (l>=beg&&r<=end) return tree[root].sum;
LL mid=l+r>>1,res=0;
down(root,mid-l+1,r-mid);
if (beg<=mid) res=(res+query(root<<1,l,mid,beg,end))%p;
if (mid<end) res=(res+query(root<<1|1,mid+1,r,beg,end))%p;
up(root);
return res;
}
int main()
{
//freopen("CODE.in","r",stdin); freopen("CODE.out","w",stdout);
register LL i;
read(n); read(m); read(p);
for (i=1;i<=n;++i)
read(a[i]);
build(1,1,n);
while (m--)
{
read(opt); read(x); read(y);
if (opt==1) read(z),modify_mul(1,1,n,x,y,z%p);
if (opt==2) read(z),modify_add(1,1,n,x,y,z%p);
if (opt==3) write(query(1,1,n,x,y)),putchar('\n');
}
return 0;
}
this question and this questionbasically similarExactly the same, double the experience (but I played twice, the right should be proficient, after all, the line segment tree is really basic and important )