日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

P3373 【模板】线段树 2(区间乘法+区间加法+区间求和)

發布時間:2023/12/15 编程问答 28 豆豆
生活随笔 收集整理的這篇文章主要介紹了 P3373 【模板】线段树 2(区间乘法+区间加法+区间求和) 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

題目描述
如題,已知一個數列,你需要進行下面三種操作:

將某區間每一個數乘上 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 的結果。
思路:雖然多了一個區間乘法,但是還是蠻難做的。今天才發現我一開始學線段樹的時候做過這道題目,但是在后面的比賽訓練種,并沒有接觸過區間乘法的題目,就給忘的一干二凈,寫篇博客記錄一下。
需要額外注意的地方:
①在pushdown的過程中,我們在計算左右子樹和的時候,采用乘法優先的原則,即規定好segtree[root* 2].value=(segtree[root* 2].value* segtree[root].mul+segtree[root].add*(本區間長度))%p。而不是加法優先的原則。
②在對區間進行加一個數的時候,沒有額外需要注意的;但是當區間乘以一個數的時候,這個區間之前加的值,也需要額外的乘以這個數字。
具體解釋看代碼:
這個代碼完全可以當作模板了^ _ ^

#include<bits/stdc++.h> #define ll long long using namespace std;const int maxx=1e5+100; struct node{int l,r;ll sum,lazyx,lazyj; }p[maxx<<2]; int n,m,q; ll a[maxx];inline void pushup(int cur) {p[cur].sum=(p[cur<<1].sum+p[cur<<1|1].sum)%q; } inline void pushdown(int cur) {p[cur<<1].sum=(p[cur<<1].sum*p[cur].lazyx+(ll)(p[cur<<1].r-p[cur<<1].l+1)*p[cur].lazyj)%q;p[cur<<1|1].sum=(p[cur<<1|1].sum*p[cur].lazyx+(ll)(p[cur<<1|1].r-p[cur<<1|1].l+1)*p[cur].lazyj)%q;//子節點的和=子節點的和乘以父節點的乘法懶惰標記+父節點的加法懶惰標記*當前區間的長度p[cur<<1].lazyj=(p[cur<<1].lazyj*p[cur].lazyx+p[cur].lazyj)%q;p[cur<<1|1].lazyj=(p[cur<<1|1].lazyj*p[cur].lazyx+p[cur].lazyj)%q;//加法的懶惰標記需要乘以父節點的乘法懶惰標記再加上父節點的加法懶惰標記p[cur<<1].lazyx=(p[cur<<1].lazyx*p[cur].lazyx)%q;p[cur<<1|1].lazyx=(p[cur<<1|1].lazyx*p[cur].lazyx)%q;p[cur].lazyj=0;p[cur].lazyx=1; } inline void build(int l,int r,int cur) {p[cur].l=l;p[cur].r=r;p[cur].lazyj=0;p[cur].lazyx=1;if(l==r){p[cur].sum=(a[l])%q;return ;}int mid=l+r>>1;build(l,mid,cur<<1);build(mid+1,r,cur<<1|1);pushup(cur); } inline void updatej(int l,int r,int cur,ll x)//更新加法 {int L=p[cur].l;int R=p[cur].r;if(l<=L&&R<=r){p[cur].lazyj+=x;p[cur].lazyj%=q;p[cur].sum+=(ll)(p[cur].r-p[cur].l+1)*x;p[cur].sum%=q;return ;}pushdown(cur);int mid=L+R>>1;if(r<=mid) updatej(l,r,cur<<1,x);else if(l>mid) updatej(l,r,cur<<1|1,x);else updatej(l,mid,cur<<1,x),updatej(mid+1,r,cur<<1|1,x);pushup(cur); } inline void updatex(int l,int r,int cur,ll x)//更新乘法 {int L=p[cur].l;int R=p[cur].r;if(l<=L&&R<=r){p[cur].sum=(p[cur].sum*x)%q;p[cur].lazyx=(p[cur].lazyx*x)%q;p[cur].lazyj=(p[cur].lazyj*x)%q;return ;}pushdown(cur);int mid=L+R>>1;if(r<=mid) updatex(l,r,cur<<1,x);else if(l>mid) updatex(l,r,cur<<1|1,x);else updatex(l,mid,cur<<1,x),updatex(mid+1,r,cur<<1|1,x);pushup(cur); } inline ll query(int l,int r,int cur)//求和 {int L=p[cur].l;int R=p[cur].r;if(l<=L&&R<=r) return p[cur].sum%q;pushdown(cur);int mid=L+R>>1;if(r<=mid) return query(l,r,cur<<1)%q;else if(l>mid) return query(l,r,cur<<1|1)%q;else return (query(l,mid,cur<<1)%q+query(mid+1,r,cur<<1|1)%q)%q; } int main() {while(~scanf("%d%d%d",&n,&m,&q)){for(int i=1;i<=n;i++) scanf("%lld",&a[i]);build(1,n,1);int x,y,z;ll k;while(m--){scanf("%d",&x);if(x==1){scanf("%d%d%lld",&y,&z,&k);updatex(y,z,1,k);}else if(x==2){scanf("%d%d%lld",&y,&z,&k);updatej(y,z,1,k);}else{scanf("%d%d",&y,&z);printf("%lld\n",query(y,z,1)%q);} }}return 0; }

努力加油a啊

總結

以上是生活随笔為你收集整理的P3373 【模板】线段树 2(区间乘法+区间加法+区间求和)的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。