洛谷3373乘法线段树

【模板】线段树 2

题目描述

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

  • 将某区间每一个数乘上 x x x
  • 将某区间每一个数加上 x x x
  • 求出某区间每一个数的和。

输入格式

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

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

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

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

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

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

输出格式

输出包含若干行整数,即为所有操作 3 3 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 % 30\% 30% 的数据: n ≤ 8 n \le 8 n8 q ≤ 10 q \le 10 q10
对于 70 % 70\% 70% 的数据:$n \le 10^3 , , q \le 10^4$。
对于 100 % 100\% 100% 的数据: 1 ≤ n ≤ 1 0 5 1 \le n \le 10^5 1n105 1 ≤ q ≤ 1 0 5 1 \le q \le 10^5 1q105

除样例外, m = 571373 m = 571373 m=571373

(数据已经过加强 _

样例说明:

故输出应为 17 17 17 2 2 2 40   m o d   38 = 2 40 \bmod 38 = 2 40mod38=2)。

AC代码

注意有加法懒惰标记plz,乘法标记mlz。
每次加法只更新plz,而乘法要更新mlz和plz。
父类的 m l z = k 1 , p l z = k 2 父类的mlz=k_1,plz=k_2 父类的mlz=k1,plz=k2,左右儿子节点有
m l z = m l z ∗ k 1 p l z = p l z ∗ k 1 + k 2 mlz=mlz*k_1\\plz=plz*k_1+k_2 mlz=mlzk1plz=plzk1+k2

#include <bits/stdc++.h>
#define ll long long
#define ls (i<<1)
#define rs (i<<1|1)
#define rep(i,a,n) for(int i=a;i<n;i++)
const int M = 100001;
template <typename T>
inline void in(T &x){
	x=0;
	int f=0;char c=getchar();
	for(;!isdigit(c);c=getchar()){ f |= c == '-';}
	for(;isdigit(c);c=getchar()){x=(x<<3)+(x<<1)+(c^48);}
	if(f)x=-x;
}
template <typename T>
inline void out(T x){
	if(x<0)putchar('-'),x=-x;
	if(x>9)out(x/10);
	putchar(x%10+'0');
}
int n,q,m,p,l,r,k;
int a[M]={0};
struct node{
	int l;
	int r;
	ll sum;
	ll mlz;
	ll plz;
	node():sum(0),plz(0),mlz(1){}
}tr[(1<<18)-1];
inline void pushdown(int i){
	if(tr[i].mlz!=1||tr[i].plz!=0){
		ll k1=tr[i].mlz,k2=tr[i].plz;
		tr[ls].sum=(tr[ls].sum*k1%m + (tr[ls].r-tr[ls].l+1)*k2%m)%m;
		tr[rs].sum=(tr[rs].sum*k1%m + (tr[rs].r-tr[rs].l+1)*k2%m)%m;
		tr[ls].plz=(tr[ls].plz*k1+k2)%m;
		tr[rs].plz=(tr[rs].plz*k1+k2)%m;
		tr[ls].mlz=tr[ls].mlz*k1%m;
		tr[rs].mlz=tr[rs].mlz*k1%m;
		tr[i].plz=0;tr[i].mlz=1;
	}
}
inline void build(int i,int L,int R){
	tr[i].l=L;tr[i].r=R;
	if(L==R){
		tr[i].sum = a[L-1];
		return;
	}
	int mid = (L+R)>>1;
	build(ls,L,mid);
	build(rs,mid+1,R);
	tr[i].sum = tr[ls].sum + tr[rs].sum;
}
inline void update_add(int i,int L,int R,int k){
	if(tr[i].l>=L&&tr[i].r<=R){
		tr[i].sum=(tr[i].sum + (tr[i].r-tr[i].l+1)*k%m)%m;
		tr[i].plz += k;
		return;
	}
	pushdown(i);
	if(tr[ls].r>=L)update_add(ls,L,R,k);
	if(tr[rs].l<=R)update_add(rs,L,R,k);
	tr[i].sum = tr[ls].sum + tr[rs].sum;
}
inline void update_mul(int i,int L,int R,int k){
	if(tr[i].l>=L&&tr[i].r<=R){
		tr[i].sum = tr[i].sum*k%m;
		tr[i].plz = tr[i].plz*k%m;
		tr[i].mlz = tr[i].mlz*k%m;
		return;
	}
	pushdown(i);
	if(tr[ls].r>=L)update_mul(ls,L,R,k);
	if(tr[rs].l<=R)update_mul(rs,L,R,k);
	tr[i].sum = tr[ls].sum + tr[rs].sum;
}
inline ll query(int i,int L,int R){
	if(tr[i].l>=L&&tr[i].r<=R)return tr[i].sum;
	if(tr[i].l>R||tr[i].r<L)return 0;
	pushdown(i);
	ll res = 0;
	if(tr[ls].r>=L)res = (res+query(ls,L,R))%m;
	if(tr[rs].l<=R)res = (res+query(rs,L,R))%m;
	return res;
}
int main(){
	in(n);in(q);in(m);
	rep(i,0,n)in(a[i]);
	build(1,1,n);
	while(q--){
		in(p);in(l),in(r);
		if(p==3){
			out(query(1,l,r));
			putchar('\n');
		}
		else if(p==1){
			in(k);update_mul(1,l,r,k);
		}
			
		else{
			in(k);update_add(1,l,r,k);
		}		
	}
	return 0;
} 
  • 23
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: Wallace树乘法器是一种高效的数字电路,用于实现乘法运算。它采用的是一种并行、分块的策略,可以快速地计算得到乘法的结果。 Wallace树乘法器的原理是把待乘数和乘数分别分组,然后通过一系列的位操作,得到最终的乘法结果。 首先,将两个乘数分别分成不同的位组,通常是3位一组。然后,对每组进行部分乘法操作,得到一个部分积。这里的部分乘法操作可以使用逻辑门电路来实现,将乘数的每一位分别与待乘数相与,得到一个乘积。 接下来,将所有的部分积相加,得到一个中间结果。这个相加的过程使用了一种特殊的加法器,叫做Wallace树加法器。这个加法器可以并行地对多个部分积进行加法运算,从而提高计算速度。 最后,将中间结果进行进位处理,得到最终的乘法结果。 Wallace树乘法器的优点是可以利用并行计算的特性,提高计算速度。它将乘法运算拆分成多个部分,每个部分可以并行进行计算,从而减少了整个乘法运算的时间复杂度。此外,Wallace树乘法器的电路结构相对简单,占用的芯片面积较小。 总之,Wallace树乘法器是一种高效的乘法器,通过并行计算的方式,可以快速得到乘法运算的结果。它在数字电路设计中有着广泛的应用。 ### 回答2: Wallace树是一种高效的乘法器结构,被广泛应用于数字电路中的乘法运算。它的原理是通过分解乘法操作,将复杂的乘法运算转化为简单的位运算和加法运算,从而提高了乘法器的速度和效率。 Wallace树的基本思想是将乘法操作分解成一个个局部的乘法和累加运算。首先,将待乘数和乘数按位分解,并将每个位进行局部乘法计算。接着,通过将不同位上的部分积进行重叠相加,产生中间的两级和。最后,将中间的两级和进行全加器的级联累加,得到最终的乘法积。 在Wallace树中,局部乘法操作通过部分积生成器来实现。部分积生成器接收两个输入信号,一个是待乘数位,一个是乘数位,并输出局部乘法的部分积。部分积生成器通过与门和异或门的组合,将输入信号进行位与运算和位异或运算,生成部分积。 通过重叠相加器,Wallace树将不同位上的部分积进行重叠相加。重叠相加器通过全加器和半加器的级联组成,实现了两级的和。将不同位上的部分积进行重叠相加后,得到了各个位上的两级和。 最后,通过级联累加器,将中间的两级和进行全加器的级联累加。级联累加器通过将全加器进行级联组合,实现了多级的累加。级联累加器最终输出的结果就是乘法运算的最终积。 总的来说,Wallace树将乘法运算分解为多个局部乘法和复杂的累加运算,利用并行运算和简单的位运算加快了乘法运算的速度和效率。它是一种高效的乘法器结构,被广泛应用于数字电路中的乘法运算。 ### 回答3: Wallace树是一种高效的乘法器实现方法,它通过将乘法操作分解成多个部分并以并行的方式计算结果。它在高速运算和低功耗方面都有着较好的性能。 Wallace树的主要原理是将输入的两个乘数进行二进制分解,并分组成多个部分。每个部分包含了若干位乘数和被乘数的片段,并通过不同的位数进行对齐。其中,被乘数的每个片段与乘数的每个片段相乘得到部分积。 接下来,部分积通过不同的处理方式进行整理和合并。Wallace树采用了区域压缩和垂直压缩的方法来减少部分积的数量,提高计算效率。在区域压缩中,相同位数的部分积进行累加得到更高位的部分积,并形成多个部分积块。在垂直压缩中,通过两两相加再组合的方式,将多个部分积块合并成更高位的结果。 最后,将合并后的结果进行进位处理,得到最终的乘法结果。 相比于传统的乘法器实现方式,Wallace树具有计算速度快和面积占用小的优势。它通过并行计算和数据压缩技术,减少了乘法操作的延迟和功耗。因此,在数字信号处理和通信等应用领域,Wallace树被广泛应用于乘法器的设计和实现中。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值