洛谷 P3373 模板 線段樹 2

2021-09-27 19:49:46 字數 1653 閱讀 2560

洛谷 p3373 【模板】線段樹 2

已知乙個數列,你需要進行下面三種操作:

1.將某區間每乙個數乘上x

2.將某區間每乙個數加上x

3.求出某區間每乙個數的和

思路:兩個lazy標記:add和mul,怎麼下放?

我遇到的問題:很多題解上來就說先乘後加比先加後乘好處理。我疑惑:如果有兩個lazy標記,不知道add和mul誰先來的,怎麼決定誰優先呢?畢竟對乙個數列先乘後加和先加後乘的結果不一樣啊。但其實,只要在做區間更新乘法的時候,把add標籤的值也乘一下,這樣就可以先乘再加了。

比如對某區間是1,2,3,4,5這個數列,詢問這個區間的和,這個區間上有兩個lazy tag,add=1,mul=5,不知道先後......

若先乘5再加1,t[p].sum=(1+2+3+4+5)*5+1+1+1+1+1=80

若先加1再乘5,t[p].sum=(2+3+4+5+6)*5=100,這種情況,我們在更新乘的時候,把add tag也乘一下,這樣對整個區間先做乘法再做加法,結果也依然正確。更新乘:此時mul=5,add=1*5=5。查詢時:t[p].sum=(1+2+3+4+5)*5+5+5+5+5+5=100!

所以關鍵就是,update_mul時,add tag也要乘k,下推標記時,子add tag也要乘上父mul tag,這樣答案就能保證正確。

(ax+b)∗c+d=acx+bc+d

這個式子告訴我們——加法懶標記不會影響乘法懶標記,但下放乘法懶標記時必須把加法懶標記也乘一下。

#includeusing namespace std;

typedef long long ll;

#define ls (p<<1)

#define rs (ls|1)

#define mid (t[p].l+t[p].r>>1)

const int n=1e5+5;

struct nodet[n<<2];

ll a[n];

int n,m;

ll mod;

inline void pushup(int p)

inline void pushdown(int p)

}void build(int p,int l,int r)

build(ls,l,mid);//build l mid

build(rs,mid+1,r);//build mid+1,r

pushup(p);

}void update_mul(int p,int l,int r,int k)

pushdown(p);

if(l<=mid) update_mul(ls,l,r,k);

if(r>mid) update_mul(rs,l,r,k);

pushup(p);

}void update_add(int p,int l,int r,int k)

pushdown(p);

if(l<=mid) update_add(ls,l,r,k);

if(r>mid) update_add(rs,l,r,k);

pushup(p);

}ll query(int p,int l,int r)

int main()else if(op[0]=='2')else

}return 0;

}

洛谷P3373 模板 線段樹2

這題有毒啊,敲了我一晚上加一早上,總算a了。由於有加和乘兩個操作,要用2個lazy陣列。核心難點就是2個lazy陣列會相互影響。因為乘影響加,加不影響乘,所以我們先算乘。include include include include include include include include i...

洛谷 P3373 模板 線段樹 2

如題,已知乙個數列,你需要進行下面三種操作 1.將某區間每乙個數乘上x 2.將某區間每乙個數加上x 3.求出某區間每乙個數的和 第一行包含三個整數n m p,分別表示該數列數字的個數 操作的總個數和模數。第二行包含n個用空格分隔的整數,其中第i個數字表示數列第i項的初始值。接下來m行每行包含3或4個...

線段樹(洛谷P3373模板2)

日常膜拜dalao 財神萬歲!話說這個線段樹今天折磨了我五個小時然後終於發現少打了乙個2.離開學還有4天然而作業一字未動絲毫不慌 ing 原題連線 洛谷線段樹模板2 要求 如題,已知乙個數列,你需要進行下面三種操作 1.將某區間每乙個數乘上x 2.將某區間每乙個數加上x 3.求出某區間每乙個數的和 ...