【luogu3373】模板 線段樹 2
題面
已知一個數列,你需要進行下面三種操作:
1.將某區間每一個數乘上x
2.將某區間每一個數加上x
3.求出某區間每一個數的和
題解
區間修改+區間查詢。
維護兩個LazyTag
#include<iostream>
#include<algorithm>
using namespace std;
const int maxn = 100010;
typedef long long LL;
int n, m;
LL a[maxn],mod;
struct node{
int l, r;
LL val, addmark, mulmark;
}sgt[maxn<<2];
void build(int p, int l, int r){
sgt[p].l = l, sgt[p].r = r;
sgt[p].mulmark=1, sgt[p].addmark=0;
if(l == r){
sgt[p].val = a[l];
}else{
int m = (l+r)/2;
build(p*2,l,m);
build(p*2+1,m+1,r);
sgt[p].val = sgt[p*2].val+sgt[p*2+1].val;
}
sgt[p].val %= mod;
}
void pushdown(int p){
if(sgt[p].addmark==0&&sgt[p].mulmark==1)return ;
//初始化父節點
LL t1 = sgt[p].addmark, t2 = sgt[p].mulmark;
sgt[p].addmark = 0, sgt[p].mulmark = 1;
//維護標記
sgt[p*2].mulmark = (sgt[p*2].mulmark*t2)%mod;
sgt[p*2+1].mulmark = (sgt[p*2+1].mulmark*t2)%mod;
sgt[p*2].addmark = (sgt[p*2].addmark*t2+t1)%mod;
sgt[p*2+1].addmark = (sgt[p*2+1].addmark*t2+t1)%mod;
//更新當前值,我們規定乘法優先更新(加法優先會損失精度)
int l = sgt[p].l, r = sgt[p].r, m = (l+r)/2;
sgt[p*2].val=(sgt[p*2].val*t2+t1*(m-l+1))%mod;//先乘以乘法標記再加上已用乘法標記更新過的加法標記。
sgt[p*2+1].val=(sgt[p*2+1].val*t2+t1*(r-m))%mod;
}
void add(int p, int l, int r, LL v){
if(l <= sgt[p].l && sgt[p].r <= r){
sgt[p].val = (sgt[p].val+(sgt[p].r-sgt[p].l+1)*v)%mod;
sgt[p].addmark = (sgt[p].addmark+v)%mod;
return ;
}
pushdown(p);
int m = (sgt[p].l+sgt[p].r)/2;
if(l <= m)add(p*2,l,r,v);
if(r > m)add(p*2+1,l,r,v);
sgt[p].val = (sgt[p*2].val+sgt[p*2+1].val)%mod;
}
void times(int p, int l, int r, LL v){
if(l <= sgt[p].l && sgt[p].r <= r){
sgt[p].val = (sgt[p].val*v)%mod;
sgt[p].mulmark = (sgt[p].mulmark*v)%mod;
sgt[p].addmark = (sgt[p].addmark*v)%mod;//原先的加法標記也要乘
return ;
}
pushdown(p);
int m = (sgt[p].l+sgt[p].r)/2;
if(l <= m)times(p*2,l,r,v);
if(r > m)times(p*2+1,l,r,v);
sgt[p].val = (sgt[p*2].val+sgt[p*2+1].val)%mod;
}
LL query(int p, int l, int r){
if(l <= sgt[p].l && sgt[p].r <= r)return sgt[p].val;
pushdown(p); //pushdown
LL m = (sgt[p].l+sgt[p].r)/2, ans = 0;
if(l <= m)ans += query(p*2,l,r);
if(r > m)ans += query(p*2+1,l,r);
return ans%mod;
}
int main(){
ios::sync_with_stdio(false);
cin>>n>>m>>mod;
for(int i = 1; i <= n; i++)cin>>a[i];
build(1,1,n);
for(int i = 1; i <= m; i++){
int op; cin>>op;
if(op == 1){
LL x, y, z; cin>>x>>y>>z;
times(1,x,y,z);
}else if(op == 2){
LL x, y, z; cin>>x>>y>>z;
add(1,x,y,z);
}else{
LL x, y; cin>>x>>y;
cout<<query(1,x,y)%mod<<"\n";
}
}
return 0;
}
寫的時候偷懶直接複製加法函式到乘法然後改。。。結果忘記改遞迴的地方了,調了半個多小時調不出來。
相關文章
- 線段樹模板
- 洛谷題單指南-線段樹-P3373 【模板】線段樹 2
- 線段樹模板總結
- P3834 【模板】可持久化線段樹 2持久化
- 【筆記/模板】線段樹(改)筆記
- [18/03/24] 線段樹模板
- 【luogu3372】線段樹 1 模板
- 暫存一下線段樹模板
- 線段樹模板重製(自寫自用)
- 【主席樹】P3919 【模板】可持久化線段樹 1持久化
- 線段樹
- 線~段~樹
- 01 線段樹
- 線段樹--RMQMQ
- 【模版】線段樹
- 線段樹 hate it
- 洛谷 P3919 可持久化線段樹 1 之主席樹模板(初級)持久化
- ut.cpp 最大線段並減線段交 [線段樹]
- 李超線段樹
- 線段樹進階
- 權值線段樹
- 線段樹筆記筆記
- Segment Tree(線段樹)
- 線段樹入門
- P4556 [Vani有約會] 雨天的尾巴 /【模板】線段樹合併
- 懶標記線段樹
- 可持久化線段樹持久化
- 線段樹(超詳解)
- 線段樹 transformation——hdu 4578ORM
- 深入理解線段樹
- 線段樹簡單思路
- 線段樹擴充套件套件
- 第二課——線段樹
- 線段樹(毒瘤)總結
- POJ 3667 Hotel 線段樹
- poj 2667 hotel 線段樹
- 線段樹 - 多組圖帶你從頭到尾徹底理解線段樹
- 資料結構之樹( 線段樹,字典樹)資料結構