线段树2(模板)

突然发现以前很多模板题没打,就过来补一补
线段树2
线 段 树 2 主 要 基 于 这 样 一 个 思 想 — — 即 乘 法 运 算 可 以 将 t a g 和 t r e e 值 同 时 乘 , 然 后 像 线 段 树 1 一 样 打 就 行 了 线段树2主要基于这样一个思想——即乘法运算可以将tag和tree值同时乘,然后像线段树1一样打就行了 线2tagtree线1

即tag1[i]为乘法打的tag,tag2[i]为加法打的tag

由 于 我 没 写 过 线 段 树 1 的 博 客 , 所 以 在 这 里 简 单 讲 一 讲 由于我没写过线段树1的博客,所以在这里简单讲一讲 线1
首 先 , 类 似 于 二 分 , 建 一 颗 树 ( 对 于 本 题 来 说 , 还 需 要 将 t a g 1 赋 值 为 1 ) 首先,类似于二分,建一颗树(对于本题来说,还需要将tag1赋值为1) tag11

void make_tree(ll l,ll r,ll p){
	if(l==r){
		tag1[p]=1;tree[p]=a[l]%mod;
		return;
	}
	ll mid=(l+r)>>1;
	make_tree(l,mid,p<<1);
	make_tree(mid+1,r,p<<1|1);
	push_up(p);tag1[p]=1;
}

一 段 区 间 ( 记 这 段 区 间 为 [ f s , s e ] ) 加 就 在 树 上 找 树 上 找 可 以 被 [ f s , s e ] 覆 盖 的 点 , 先 将 t r e e 值 中 的 每 个 数 加 上 v a l ( 更 新 的 值 ) , 即 t r e e + = v a l ∗ ( r − l + 1 ) , 然 后 再 把 t a g 2 的 值 加 v a l 就 行 了 ( p u s h d o w n 后 面 再 具 体 解 释 ) 一段区间(记这段区间为[fs,se])加就在树上找树上找可以被[fs,se]覆盖的点,先将tree值中的每个数加上val(更新的值),即tree+=val*(r-l+1),然后再把tag2的值加val就行了(pushdown后面再具体解释) [fs,se][fs,se]treevaltree+=valrl+1tag2val(pushdown)

void uppdate1(ll l,ll r,ll p,ll fs,ll se,ll val){
	if(fs<=l&&r<=se){
		tree[p]=(1ll*tree[p]*(val))%mod;
		tag1[p]=1ll*(tag1[p]*val)%mod;tag2[p]=1ll*(tag2[p]*val)%mod;
		return;
	}
	if((tag1[p]!=1)||(tag2[p]!=0)) pushdown(l,r,p);
	ll mid=(l+r)>>1;
	if(fs<=mid) uppdate1(l,mid,p<<1,fs,se,val);
	if(se>mid)  uppdate1(mid+1,r,p<<1|1,fs,se,val);
	push_up(p);
}

一 段 区 间 ( 记 这 段 区 间 为 [ f s , s e ] ) 乘 , 就 把 可 以 覆 盖 到 的 树 上 的 点 的 t r e e 值 乘 上 v a l ( 乘 法 改 变 的 值 ) , 同 时 将 t a g 2 和 t a g 1 乘 上 v a l , 因 为 t r e e [ i ] 的 子 树 中 的 任 意 点 j 的 实 际 值 都 是 t r e e [ j ] ∗ t a g 1 [ j ] + t a g 2 [ j ] ∗ ( r j − l j + 1 ) , 即 a ∗ ( b + c ) = a ∗ ( b ) + a ∗ ( c ) , 所 以 我 们 直 接 将 需 要 加 的 值 和 原 值 乘 上 v a l 即 可 一段区间(记这段区间为[fs,se])乘,就把可以覆盖到的树上的点的tree值乘上val(乘法改变的值),同时将tag2和tag1乘上val,因为tree[i]的子树中的任意点j的实际值都是tree[j]*tag1[j]+tag2[j]*(r_j-l_j+1),即a*(b+c)=a*(b)+a*(c),所以我们直接将需要加的值和原值乘上val即可 [fs,se]treevaltag2tag1valtree[i]jtree[j]tag1[j]+tag2[j](rjlj+1),ab+c=a(b)+a(c),val

void uppdate2(ll l,ll r,ll p,ll fs,ll se,ll val){
	if(fs<=l&&r<=se){
		tree[p]=(((r-l+1)%mod)*val%mod+tree[p]%mod)%mod;
		tag2[p]=1ll*(tag2[p]%mod+val)%mod;
		return;
	}
	if((tag1[p]!=1)||(tag2[p]!=0)) pushdown(l,r,p);
	ll mid=(l+r)>>1;
	if(fs<=mid) uppdate2(l,mid,p<<1,fs,se,val);
	if(se>mid)  uppdate2(mid+1,r,p<<1|1,fs,se,val);
	push_up(p);
}

因为要加的值已经乘过了,所以pushdown时先乘再加(这里一个小错误我调了很久)

void pushdown(ll l,ll r,ll p){
     ll mid=((l+r)>>1);
	 tag1[p<<1]=1ll*(tag1[p<<1]*tag1[p])%mod;tag2[p<<1]=(tag2[p<<1]*tag1[p]+tag2[p])%mod;
     tag1[p<<1|1]=1ll*(tag1[p<<1|1]*tag1[p])%mod;tag2[p<<1|1]=1ll*(tag2[p<<1|1]*tag1[p]+tag2[p])%mod;
     tree[p<<1]=(1ll*tree[p<<1]*tag1[p]%mod+(tag2[p]*((mid-l+1)%mod)%mod))%mod;/*区间中的每个数都要加tag[2]*/
     tree[p<<1|1]=(1ll*tree[p<<1|1]*tag1[p]%mod+(tag2[p]*((r-mid)%mod)%mod))%mod;/*区间中的每个数都要加tag[2]*/
     tag1[p]=1,tag2[p]=0;
}
#include<bits/stdc++.h>
using namespace std;

typedef long long ll;
const ll N=1e5+5;
ll n,m,mod;
ll tree[N*4],tag1[N*4],tag2[N*4],a[N];
void push_up(ll p){
	tree[p]=(tree[p<<1]+tree[p<<1|1])%mod;
}
void make_tree(ll l,ll r,ll p){
	if(l==r){
		tag1[p]=1;tree[p]=a[l]%mod;
		return;
	}
	ll mid=(l+r)>>1;
	make_tree(l,mid,p<<1);
	make_tree(mid+1,r,p<<1|1);
	push_up(p);tag1[p]=1;
}
void pushdown(ll l,ll r,ll p){
     ll mid=((l+r)>>1);
	 tag1[p<<1]=1ll*(tag1[p<<1]*tag1[p])%mod;tag2[p<<1]=(tag2[p<<1]*tag1[p]+tag2[p])%mod;
     tag1[p<<1|1]=1ll*(tag1[p<<1|1]*tag1[p])%mod;tag2[p<<1|1]=1ll*(tag2[p<<1|1]*tag1[p]+tag2[p])%mod;
     tree[p<<1]=(1ll*tree[p<<1]*tag1[p]%mod+(tag2[p]*((mid-l+1)%mod)%mod))%mod;/*区间中的每个数都要加tag[2]*/
     tree[p<<1|1]=(1ll*tree[p<<1|1]*tag1[p]%mod+(tag2[p]*((r-mid)%mod)%mod))%mod;/*区间中的每个数都要加tag[2]*/
     tag1[p]=1,tag2[p]=0;
}
void uppdate1(ll l,ll r,ll p,ll fs,ll se,ll val){
	if(fs<=l&&r<=se){
		tree[p]=(1ll*tree[p]*(val))%mod;
		tag1[p]=1ll*(tag1[p]*val)%mod;tag2[p]=1ll*(tag2[p]*val)%mod;
		return;
	}
	if((tag1[p]!=1)||(tag2[p]!=0)) pushdown(l,r,p);
	ll mid=(l+r)>>1;
	if(fs<=mid) uppdate1(l,mid,p<<1,fs,se,val);
	if(se>mid)  uppdate1(mid+1,r,p<<1|1,fs,se,val);
	push_up(p);
}
void uppdate2(ll l,ll r,ll p,ll fs,ll se,ll val){
	if(fs<=l&&r<=se){
		tree[p]=(((r-l+1)%mod)*val%mod+tree[p]%mod)%mod;
		tag2[p]=1ll*(tag2[p]%mod+val)%mod;
		return;
	}
	if((tag1[p]!=1)||(tag2[p]!=0)) pushdown(l,r,p);
	ll mid=(l+r)>>1;
	if(fs<=mid) uppdate2(l,mid,p<<1,fs,se,val);
	if(se>mid)  uppdate2(mid+1,r,p<<1|1,fs,se,val);
	push_up(p);
}
ll ans=0;
void query(ll l,ll r,ll p,ll fs,ll se){
	if(fs<=l&&r<=se){
	    ans=(ans+tree[p])%mod;
	    return;
	}
	if(tag1[p]!=1||tag2[p]!=0) pushdown(l,r,p);
	ll mid=(l+r)>>1;
	if(fs<=mid) query(l,mid,p<<1,fs,se);
	if(se>mid)  query(mid+1,r,p<<1|1,fs,se);
	push_up(p);
}
int main(){
	scanf("%lld%lld%lld",&n,&m,&mod);
	for(ll i=1;i<=n;i++){
		scanf("%lld",&a[i]);
	}
	make_tree(1,n,1);
	for(ll i=1;i<=m;i++){
		ll tp;
		scanf("%lld",&tp);
		if(tp==1){
			ll x,y;
			ll k;
			scanf("%lld%lld%lld",&x,&y,&k);k%=mod;
		    uppdate1(1,n,1,x,y,k);
		}
		if(tp==2){
			ll x,y;
			ll k;
			scanf("%lld%lld%lld",&x,&y,&k);k%=mod;
			uppdate2(1,n,1,x,y,k);
		}
		if(tp==3){
			ll x,y;
			ans=0;
			scanf("%lld%lld",&x,&y);
		    query(1,n,1,x,y);
		    printf("%lld\n",ans);
		}
	}
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值