這題乍一看以爲好難啊,而後咱們來仔細分析一下題目函數
題目說有兩種修改操做ui
1.區間加某一值
2.區間乘某一值spa
首先想到的思路必定是打兩個$lazymark$
男就男在這兩個操做有前後,我$ri$,那麼咱們就應該來仔細看一下前後順序對程序的影響code
順序無非就是兩種:blog
1.先乘後加
先乘後加和數學同樣,因此咱們來先看一下這種
$tree[ls].date=(tree[ls].date\times tree[x].cheng % p+tree[x].jia\times (r-l+1) % p) % p $
如此看來咱們改變$cheng$的值時,只須要把$jia$去乘一下$cheng$就好了
這樣來看好像很對.........其實就是很對get
2.先加後乘
那麼咱們來看一下這個
$tree[ls].date=(tree[ls].date+ tree[x].jia)\cdot tree[root].cheng % p $
這樣子的化就無法向上面的代碼同樣更新$cheng$時去維護$jia$了數學
看完這裏就沒什麼難的了,就是要寫兩個$update$去分別維護$cheng,jia$兩個$lazymark$string
上面的代碼顯示不全,就放張圖吧
來詳細解釋(口胡)一波:
如下解釋不針對題目只是口胡一波
如今咱們要對區間$[l,r]$進行一坨的加和乘的操做
先把它當作加法優先的狀況
$(sum+lazy_{jia}) \times lazy_{cheng}$
很容易看出來
若是我更新了$ lazy_{cheng}$那麼$lazy_{jia}$也要改變因此咱們變形一下
$(sum \times lazy_{cheng})+lazy_{jia}*lazy_{cheng}$
設$sjpnb=lazy_{jia}*lazy_{cheng}$
那麼就變成了;
$(sum \times lazy_{cheng})+sjpnb$
如此來看$lazy_{cheng}$改變就不會致使$lazy_{jia}$變了
咱們把$sjpnb$當作$lazy_{jia}$不就ok了?
口胡完成有什麼錯誤請見諒,畢竟人家是菜雞嗎
代碼寫的可能複雜了些,$putdown$函數寫的有點複雜了,其實不必像我這樣寫
#include<iostream> #include<cstdio> #include<algorithm> #include<cmath> #include<queue> #include<stack> #include<vector> #include<map> #include<string> #include<cstring> #define int long long int #define lowbit(x) x & -x const int N=100000; using namespace std; inline int read() { char c = getchar(); int x = 0, f = 1; while(c < '0' || c > '9') { if(c == '-') f = -1; c = getchar(); } while(c >= '0' && c <= '9') x = x * 10 + c - '0', c = getchar(); return x * f; } int n,m,p,a[N*4]; struct node { int date; int cheng; int jia; } tree[N*4+10]; void pushup(int root) { tree[root].date=(tree[root<<1].date+tree[root<<1|1].date)%p; } void build(int root,int l,int r) { tree[root].cheng=1; if(l==r) { tree[root].date=a[l]; return ; } int mid=(l+r)/2; build(root<<1,l,mid); build(root<<1|1,mid+1,r); pushup(root); } void pushdown(int x,int l,int r) { int ls=x<<1,rs=x<<1|1,mid=(l+r)>>1; tree[ls].date=(tree[ls].date*tree[x].cheng%p+tree[x].jia*(mid-l+1)%p)%p; tree[ls].cheng=(tree[ls].cheng*tree[x].cheng)%p; tree[ls].jia=(tree[ls].jia*tree[x].cheng+tree[x].jia)%p; tree[rs].date=(tree[rs].date*tree[x].cheng%p+tree[x].jia*(r-(mid+1)+1)%p)%p; tree[rs].cheng=(tree[rs].cheng*tree[x].cheng)%p; tree[rs].jia=(tree[rs].jia*tree[x].cheng+tree[x].jia)%p; tree[x].jia=0; tree[x].cheng=1; return; } void update_cheng(int root,int l,int r,int x,int y,int k) { if(r<x || l>y) return ; if(l>=x & r<=y) { tree[root].date=(tree[root].date*k)%p; tree[root].cheng=(tree[root].cheng*k)%p; tree[root].jia=(tree[root].jia*k)%p; return; } pushdown(root,l,r); int mid=(l+r)>>1; update_cheng(root<<1,l,mid,x,y,k); update_cheng(root<<1|1,mid+1,r,x,y,k); pushup(root); } void update_jia(int root,int l,int r,int x,int y,int k) { if(r<x || l>y) return ; if(l>=x & r<=y) { tree[root].date=(tree[root].date+k*(r-l+1)%p)%p; tree[root].jia=(tree[root].jia+k)%p; return; } pushdown(root,l,r); int mid=(l+r)>>1; update_jia(root<<1,l,mid,x,y,k); update_jia(root<<1|1,mid+1,r,x,y,k); pushup(root); } int query(int root,int l,int r,int x,int y) { if(r<x || l>y) return 0; if(l>=x && r<=y) { return tree[root].date; } pushdown(root,l,r); int mid=(l+r)>>1; return (query(root<<1,l,mid,x,y)+query(root<<1|1,mid+1,r,x,y))%p; } signed main() { scanf("%lld %lld %lld",&n,&m,&p); for(int i=1; i<=4*n; i++) tree[i].cheng=1; for(int i=1; i<=n; i++) { scanf("%lld",&a[i]); } build(1,1,n); int opt,x,y,k; while(m--) { scanf("%lld",&opt); if(opt==1) { scanf("%lld %lld %lld",&x,&y,&k); update_cheng(1,1,n,x,y,k); } if(opt==2) { scanf("%lld %lld %lld",&x,&y,&k); update_jia(1,1,n,x,y,k); } if(opt==3) { scanf("%lld %lld",&x,&y); cout<<query(1,1,n,x,y)%p<<endl; } } return 0; }