【模板】线段树 2 洛谷P3373

题目描述

如题,已知一个数列,你需要进行下面三种操作:

  • 将某区间每一个数乘上 xx

  • 将某区间每一个数加上 xx

  • 求出某区间每一个数的和

输入格式

第一行包含三个整数 n,m,pn,m,p,分别表示该数列数字的个数、操作的总个数和模数。

第二行包含 nn 个用空格分隔的整数,其中第 ii 个数字表示数列第 ii 项的初始值。

接下来 mm 行每行包含若干个整数,表示一个操作,具体如下:

操作 11: 格式:1 x y k 含义:将区间 [x,y][x,y] 内每个数乘上 kk

操作 22: 格式:2 x y k 含义:将区间 [x,y][x,y] 内每个数加上 kk

操作 33: 格式:3 x y 含义:输出区间 [x,y][x,y] 内每个数的和对 pp 取模所得的结果

输出格式

输出包含若干行整数,即为所有操作 33 的结果。

输入输出样例

输入 #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\%30% 的数据:n \le 8n≤8,m \le 10m≤10
对于 70\%70% 的数据:n \le 10^3n≤103,m \le 10^4m≤104
对于 100\%100% 的数据:n \le 10^5n≤105,m \le 10^5m≤105

除样例外,p = 571373p=571373

(数据已经过加强^_^)

样例说明:

故输出应为 17

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int MAXN = 100010;
int p,in[MAXN];
struct Segment_Tree{
	struct info{
		int l,r,plz,mlz = 1;
		ll sum;
	}node[MAXN << 2];
	void Build(int n,int l,int r){
		node[n].l = l,node[n].r = r;
		if(l == r){
			node[n].sum = in[l];
			return;
		}
		int mid = (l+r) >> 1;
		Build(n << 1,l,mid);
		Build(n << 1|1,mid+1,r);
		node[n].sum = (node[n << 1].sum + node[n << 1|1].sum) % p;
		return;
	}
	inline void push_down(int i){
		ll k1 = node[i].plz,k2 = node[i].mlz;
		int lt = i << 1,rt = i << 1|1;
		node[lt].sum = (node[lt].sum*k2 + k1*(node[lt].r - node[lt].l + 1) % p) % p;
		node[rt].sum = (node[rt].sum*k2 + k1*(node[rt].r - node[rt].l + 1) % p) % p;
		node[lt].mlz = (node[lt].mlz*k2) % p;
		node[rt].mlz = (node[rt].mlz*k2) % p;
		node[lt].plz = (node[lt].plz*k2+k1) % p;
		node[rt].plz = (node[rt].plz*k2+k1) % p;
		node[i].plz = 0;
		node[i].mlz = 1;
		return;
	}
	void plu(int i,int l,int r,ll k){
		if(node[i].l >= l && node[i].r <= r){
			node[i].sum = (node[i].sum + k*(node[i].r - node[i].l + 1) % p) % p;
			node[i].plz = (node[i].plz + k) % p;
			return;
		}
		push_down(i);
		int lt = i << 1,rt = i << 1|1;
		if(node[lt].r >= l) plu(lt,l,r,k);
		if(node[rt].l <= r) plu(rt,l,r,k);
		node[i].sum = (node[lt].sum + node[rt].sum) % p;
		return;
	}
	void mul(int i,int l,int r,ll k){
		if(node[i].l >= l && node[i].r <= r){
			node[i].sum = (node[i].sum * k) % p;
			node[i].mlz = (node[i].mlz * k) % p;
			node[i].plz = (node[i].plz * k) % p;
			return;
		}
		push_down(i);
		int lt = i << 1,rt = i << 1|1;
		if(node[lt].r >= l) mul(lt,l,r,k);
		if(node[rt].l <= r) mul(rt,l,r,k);
		node[i].sum = (node[lt].sum + node[rt].sum) % p;
	}
	inline ll query(int i,int l,int r){
		if(node[i].l >= l && node[i].r <= r) return node[i].sum;
		if(node[i].r < l && node[i].l > r) return 0;
		push_down(i);
		ll s = 0;
		int lt = i << 1,rt = i << 1|1;
		if(node[lt].r >= l) s = (s + query(lt,l,r)) % p;
		if(node[rt].l <= r) s = (s + query(rt,l,r)) % p;
		return s % p;
	}
}ST;
int main()
{
	int n,m,t,x,y,k;
	scanf("%d %d %d",&n,&m,&p);
	for(int i = 1;i <= n; i++)
		scanf("%d",&in[i]);
	ST.Build(1,1,n);
	while(m--){
		scanf("%d",&t);
		if(t == 1){
			scanf("%d %d %d",&x,&y,&k);
			ST.mul(1,x,y,k);
		}
		if(t == 2){
			scanf("%d %d %d",&x,&y,&k);
			ST.plu(1,x,y,k);
		}
		if(t == 3){
			scanf("%d %d",&x,&y);
			ll res = ST.query(1,x,y);
			printf("%lld\n",res);
		}
	}
	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值