P3373 【模板】线段树 2

时间:2022-06-20
本文章向大家介绍P3373 【模板】线段树 2,主要内容包括其使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。

P3373 【模板】线段树 2

乘法优先还是加法优先

①加法优先,即规定好segtree[root*2].value=((segtree[root*2].value+segtree[root].add)*segtree[root].mul)%p,问题是这样的话非常不容易进行更新操作,假如改变一下add的数值,mul也要联动变成奇奇怪怪的分数小数损失精度,我们内心是很拒绝的;

②乘法优先,即规定好segtree[root*2].value=(segtree[root*2].value*segtree[root].mul+segtree[root].add*(本区间长度))%p,这样的话假如改变add的数值就只改变add,改变mul的时候把add也对应的乘一下就可以了,没有精度损失,看起来很不错。

(来自洛谷第一篇分析)

#include <bits/stdc++.h>
using namespace std;
#define ll long long
const int maxn = 100005;
ll mod;
ll a[maxn];
struct Node{
	int l,r;
	ll pre,add,mul;
}t[4*maxn+5];
void build(int p,int l,int r){
	t[p].l = l; t[p].r = r;
	if(l==r){
		t[p].pre = a[l]; t[p].mul = 1;
		return ;
	}
	t[p].mul = 1;
	int mid = l+r>>1;
	build(p*2,l,mid);
	build(p*2+1,mid+1,r);
	t[p].pre = (t[2*p].pre + t[2*p+1].pre)%mod;
}
void spread(int p){
	
		t[2*p].pre = (t[2*p].pre*t[p].mul + t[p].add*(t[2*p].r-t[2*p].l+1))%mod;
		t[2*p+1].pre = (t[2*p+1].pre*t[p].mul + t[p].add*(t[2*p+1].r-t[2*p+1].l+1))%mod;
		t[2*p].mul = (t[p].mul*t[2*p].mul)%mod;
		t[2*p+1].mul = (t[p].mul*t[2*p+1].mul)%mod;
		t[2*p].add = (t[2*p].add*t[p].mul+t[p].add)%mod;
		t[2*p+1].add = (t[2*p+1].add*t[p].mul+t[p].add)%mod;
		t[p].mul = 1;
		t[p].add = 0;

}
void change1(int p,int l,int r,ll z){//加法更新 
	if(l<=t[p].l&&r>=t[p].r){
		t[p].pre+=z*(t[p].r-t[p].l+1);t[p].pre%=mod;
		t[p].add+=z;t[p].add%=mod;//加法只处理加法 
		return ;
	}
	spread(p);
	int mid = t[p].l+t[p].r>>1;
	if(l<=mid)change1(p*2,l,r,z);
	if(r>mid)change1(p*2+1,l,r,z);
	t[p].pre = (t[2*p].pre + t[2*p+1].pre)%mod;
}

void change2(int p,int l,int r,ll z){//乘法更新 
	if(l<=t[p].l&&r>=t[p].r){
		t[p].pre=(t[p].pre*z)%mod;
		t[p].mul=(t[p].mul*z)%mod;
		t[p].add=(t[p].add*z)%mod;//乘法  则加全都乘 
		return ;
	}
	spread(p);
	int mid = t[p].l + t[p].r>>1;
	if(l<=mid)change2(p*2,l,r,z);
	if(r>mid)change2(p*2+1,l,r,z);
	t[p].pre = (t[2*p].pre+t[2*p+1].pre)%mod; 
}

ll query(int p,int l,int r){
	if(l<=t[p].l&&r>=t[p].r){
		return t[p].pre%mod;
	}
	spread(p);
	ll ans = 0;
	int mid = t[p].l + t[p].r>>1;
	if(l<=mid)ans+=query(p*2,l,r),ans%=mod;
	if(r>mid)ans+=query(p*2+1,l,r),ans%=mod;
	
	return ans;
} 

int main()
{
	 int n, m;
    scanf("%d%d%lld", &n, &m, &mod);
    for(int i=1; i<=n; i++){
        scanf("%lld", &a[i]);
    }
    build(1, 1, n);
    while(m--){
        int chk;
        scanf("%d", &chk);
        int x, y;
        ll k;
        if(chk==1){
            scanf("%d%d%lld", &x, &y, &k);
            change2(1,x,y,k);
        }
        else if(chk==2){
            scanf("%d%d%lld", &x, &y, &k);
            change1(1,x,y,k);
        }
        else{
            scanf("%d%d", &x, &y);
            printf("%lldn", query(1,x,y));
        }
    }
    return 0;
 }