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;
}
posted @ 2023-04-05 11:12  N0zoM1z0  阅读(8)  评论(0编辑  收藏  举报