P3373 线段树模板 2
【模板】线段树 2
题目描述
如题,已知一个数列,你需要进行下面三种操作:
-
将某区间每一个数乘上 \(x\)
-
将某区间每一个数加上 \(x\)
-
求出某区间每一个数的和
输入格式
第一行包含三个整数 \(n,m,p\),分别表示该数列数字的个数、操作的总个数和模数。
第二行包含 \(n\) 个用空格分隔的整数,其中第 \(i\) 个数字表示数列第 \(i\) 项的初始值。
接下来 \(m\) 行每行包含若干个整数,表示一个操作,具体如下:
操作 \(1\): 格式:1 x y k
含义:将区间 \([x,y]\) 内每个数乘上 \(k\)
操作 \(2\): 格式:2 x y k
含义:将区间 \([x,y]\) 内每个数加上 \(k\)
操作 \(3\): 格式:3 x y
含义:输出区间 \([x,y]\) 内每个数的和对 \(p\) 取模所得的结果
输出格式
输出包含若干行整数,即为所有操作 \(3\) 的结果。
样例 #1
样例输入 #1
5 5 38
1 5 4 2 3
2 1 4 1
3 2 5
1 2 4 2
2 3 5 5
3 1 4
样例输出 #1
17
2
提示
【数据范围】
对于 \(30\%\) 的数据:\(n \le 8\),\(m \le 10\)
对于 \(70\%\) 的数据:$n \le 10^3 \(,\) m \le 10^4$
对于 \(100\%\) 的数据:$ n \le 10^5\(,\) m \le 10^5$
除样例外,\(p = 571373\)
样例说明:
故输出应为 \(17\)、\(2\)( \(40 \bmod 38 = 2\) )
复习线段树
首先注意 线段树 维护 l r sum add mul
先乘法后加法 乘法懒标记mul修改时直接×mul即可
但是 加法懒标记add修改时 要add×mul+add
还有一个点:build的时候 if(l==r)tr[p].sum=a[l] 不要手贱写成a[p]……
#include<bits/stdc++.h>//Segment Tree
using namespace std;
#define int long long
inline int read()
{
int x=0,f=1;
char ch=getchar();
while(ch<48||ch>57)
{
if(ch=='-')f=-1;
ch=getchar();
}
while(ch=48&&ch<=57)
{
x=10*x+ch-48;
ch=getchar();
}
return x*f;
}
const int N=1e5+5;
struct SegTree{
int sum,add,mul,l,r;//mul first add next
}tr[N<<2];
int n,m,mod,a[N];
void pushup(int p)
{
tr[p].sum=tr[p<<1].sum+tr[p<<1|1].sum;
tr[p].sum=(tr[p].sum%mod+mod)%mod;
// tr[p].sum%=mod;
}
void pushdown(int p)
{
tr[p<<1].sum=tr[p<<1].sum*tr[p].mul+(tr[p<<1].r-tr[p<<1].l+1)*tr[p].add;
tr[p<<1].mul*=tr[p].mul;
tr[p<<1].add=tr[p<<1].add*tr[p].mul+tr[p].add;
tr[p<<1].sum=(tr[p<<1].sum%mod+mod)%mod;
tr[p<<1].mul=(tr[p<<1].mul%mod+mod)%mod;
tr[p<<1].add=(tr[p<<1].add%mod+mod)%mod;
tr[p<<1|1].sum=tr[p<<1|1].sum*tr[p].mul+(tr[p<<1|1].r-tr[p<<1|1].l+1)*tr[p].add;
tr[p<<1|1].mul*=tr[p].mul;
tr[p<<1|1].add=tr[p<<1|1].add*tr[p].mul+tr[p].add;
tr[p<<1|1].sum=(tr[p<<1|1].sum%mod+mod)%mod;
tr[p<<1|1].mul=(tr[p<<1|1].mul%mod+mod)%mod;
tr[p<<1|1].add=(tr[p<<1|1].add%mod+mod)%mod;
tr[p].add=0,tr[p].mul=1;
}
void build(int p,int l,int r)
{
tr[p].l=l,tr[p].r=r;tr[p].add=0,tr[p].mul=1;
if(l==r)
{
tr[p].sum=a[l];
return ;
}
int mid=(l+r)>>1;
build(p<<1,l,mid);
build(p<<1|1,mid+1,r);
pushup(p);
}
void modify(int p,int l,int r,int add,int mul)
{
if(l<=tr[p].l&&r>=tr[p].r)
{
tr[p].sum=tr[p].sum*mul+(tr[p].r-tr[p].l+1)*add;
tr[p].mul*=mul;
tr[p].add=tr[p].add*mul+add;
tr[p].sum=(tr[p].sum%mod+mod)%mod;
tr[p].mul=(tr[p].mul%mod+mod)%mod;
tr[p].add=(tr[p].add%mod+mod)%mod;
return ;
}
pushdown(p);
int mid=(tr[p].l+tr[p].r)>>1;
if(l<=mid)modify(p<<1,l,r,add,mul);
if(r>mid)modify(p<<1|1,l,r,add,mul);
pushup(p);
}
int query(int p,int l,int r)
{
int sum=0;
if(l<=tr[p].l&&r>=tr[p].r)return tr[p].sum;
int mid=(tr[p].l+tr[p].r)>>1;
pushdown(p);
if(l<=mid)sum+=query(p<<1,l,r);
if(r>mid)sum+=query(p<<1|1,l,r);
return (sum%mod+mod)%mod;
}
signed main()
{
ios::sync_with_stdio(false);
cin>>n>>m>>mod;
for(int i=1;i<=n;i++)cin>>a[i];
build(1,1,n);
// cout<<tr[1].sum<<"\n\n";
for(int i=1;i<=m;i++)
{
int op,x,y,k;
cin>>op>>x>>y;
if(op==1)
{
// k=read();
cin>>k;
modify(1,x,y,0,k);
}
if(op==2)
{
// k=read();
cin>>k;
modify(1,x,y,k,1);
}
if(op==3)
{
int sum=query(1,x,y);
cout<<(sum%mod+mod)%mod<<"\n";
}
}
return 0;
}