線段樹模板 洛谷P2023

2021-09-01 02:39:00 字數 1646 閱讀 4245

傳送門:

這個題目的區間更新有加法和乘法。

所以比裸的線段樹難一點點吧,也就僅僅是一點點。

既然存在兩個操作,所以我們就要維護兩個tag,乙個加法乙個乘法。

但是pushdown的時候這兩個tag怎麼pushdown呢?

乘法的優先順序顯然比加法高,所以我們在mul更新的時候要先pushdown,這是乙個要點。第二個要點就是,pushdown的時候,對於乘法tag,我們可以直接乘上父節點的tag,但是對於加法的,我們要怎麼辦呢?   我們要先把該結點的tag乘上乘法tag,然後再加上父節點的tag。為什麼要這樣做呢?因為乘法優先順序高的嘛,這樣就完事了。

看不懂的話,下面我就來推導一下

假設父節點是ax+b

我們要pushdown左兒子。

我們要乘乙個k然後加上c

就變成了k(ax+b)+c

變成了kax+kb+c

變成了(ka)x+(kb+c)

右邊的kb+c就變成了add[rt<<1]*mul[rt]+add[rt]。ka就是mul[rt<<1]*mul[rt]。

下面是每次都比分塊慢的線段樹**:

(分塊寫這種區間更新的,不如線段樹方便,我就沒寫分塊的**。)

#include using namespace std;

typedef long long ll;

const int maxn = 1e6+7;

ll a[maxn];

ll sum[maxn<<2],add[maxn<<2],mul[maxn<<2];

ll n,p;

void pushup(int rt)

void pushdown(int rt,int ln,int rn)

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

int mid = (l+r)/2;

build(rt<<1,l,mid);

build(rt<<1|1,mid+1,r);

pushup(rt);

}void add(int x,int y,int l,int r,int rt,int v)

int mid = (l+r)/2;

pushdown(rt,mid-l+1,r-mid);

if(x<=mid)

if(y>mid)

pushup(rt);

}void mul(int x,int y,int l,int r,int rt,int v)

if(x<=mid)

if(y>mid)

pushup(rt);

}ll query(int x,int y,int l,int r,int rt)

int mid = (l+r)/2;

pushdown(rt,mid-l+1,r-mid);

ll ans = 0;

if(x<=mid)

if(y>mid)

return ans;

}int main()

build(1,1,n);

int m;

scanf("%d",&m);

for(int i=0;ielse if(t==2)

else

}return 0;

}

洛谷P3372 線段樹模板

線段樹講的很詳細的部落格 鏈結 includeusing namespace std typedef long long ll const int maxn 100005 ll dat maxn 儲存資料 ll tree maxn 2 儲存線段樹的陣列常開成資料的4倍大小 ll add maxn 2...

線段樹模板(洛谷P3372)

給定序列,支援區間加 求區間和。線段樹的基本思路 線段樹模板嘛,不懂得看題解第一,dalao講解超詳細的 includeusing namespace std define ll long long int maxn 1000001 unsigned ll n,m,a maxn ans maxn 2...

洛谷P3373 模板 線段樹2

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