基礎線段樹

2022-07-19 03:36:12 字數 4499 閱讀 5540

設\(mtag\)為乘法標記,\(atag\)為加法標記

對於下放後的每乙個區間來說,\(x=x*mtag+atag*len\)(式\(1\))

再根據前面的式\(1\),易得

\(mtag_2 = mtag_1\cdot mtag_2\)

\(atag_2=atag_2\cdot mtag_1+atag_2\)

核心(下放)**:

void pushdown(tree2 *tree,int l,int r)
p4145 上帝造題的七分鐘2 / 花神遊歷各國p6327 區間加區間sin和p1438 無聊的數列p4513 小白逛公園

p4588 [tjoi2018]數學計算

p2894 [usaco08feb]hotel g

照題裡的這個資料範圍來看,直接暴力開方肯定會t飛

通過觀察,不難發現資料範圍內最大的數也只需要\(6\)次開方就可以變為\(1\)

考慮剪枝優化:

當乙個區間的最大值為\(1\)時,其整個區間的其他值肯定也為\(1\)

因此當區間內最大值等於\(1\)時,直接\(return\)掉

核心**:

void change(int node,int l,int r)

int mid = (l+r)>>1;

if(l<=mid&&tree[lson].maxn>1)

if(r>mid&&tree[rson].maxn>1)

pushup(node);

}

挺好的一道題目,很適合線段樹初學者練手

學過和差角公式的應該都能很快想出解法

\(sin(a+x) = sinacosx+cosasinx\)

\(cos(a+x) = cosacosx-sinxsina\)

核心**:

void update2(int node,double sinv,double cosv)

void pushdown(int node)

return;

}void change(int node,int l,int r,int x)

pushdown(node);//下放

int mid = (l + r)>>1;

if(l<=mid) change(lson,l,r,x);

if(r>mid) change(rson,l,r,x);

update(node);//上傳更新

return;

}

利用線段樹來維護差分陣列。

每當進行乙個操作\(1\)時

將點\(l\)加上首相\(k\)

如果區間不是乙個點的話,則將區間\([l+1,r]\)上的點都加上公差\(d\)

如果\(r,則在\(r+1\)的位置上加上\(-(k+(r-l)\cdot d))\),便於差分

查詢時,將區間\([1,k]\)的值都加上即可,相當於查詢操作

區間查詢,區間修改,直接上線段樹模板即可

核心**:

for(int i=1;i<=m;i++)

else

}

線段樹經典題

維護乙個從區間左端點開始的區間最大子段\(maxl\),從右端點開始的區間最大子段\(maxr\),總區間最大子段\(maxx\),和乙個區間和\(sum\)

對於\(maxl\)來說,其右端點的位置有兩種可能:

得到方程:\(tree.maxl = max(lson.maxl,lson.sum+rson.maxl)\)

\(maxr\)也同理

方程:\(tree.maxr = max(rson.maxr,rson.sum+lson.maxr)\)

對於\(maxx\)來說,其區間範圍有三種可能

得到方程:\(tree.maxx = max(lson.maxx,rson.maxx,lson.maxr+rson.maxl))\)

查詢時只需輸出區間\([l,r]\)中的\(maxx\)即可

核心**:

更新操作

void update(tree2 *tree,tree2 *lson,tree2 *rson)
查詢操作

tree2 *query(tree2 *tree,int l,int r,int x,int y)
比較簡單的一道題目。

仔細觀察不難發現

所謂的操作\(1\)跟操作\(2\)其實就是在進行普通的單點修改操作而已

用乙個線段樹在記錄一段區間內的總乘積

操作\(1\)是把點\(i\)的值從\(1\)修改為\(i\)

操作\(2\)則是把點\(pos\)的值修改為\(1\)

核心**:

void pushup(int node)

void build(int node,int l,int r)

long long mid = (l + r)>>1;

build(lson,l,mid);

build(rson,mid+1,r);

pushup(node);

}void change(int node,int l,int r,int x,int y)

int mid = (l + r)>>1;

if(x<=mid) change(lson,l,mid,x,y);

else change(rson,mid+1,r,x,y);

pushup(node);

}

p4513 小白逛公園大同小異的思路

只是把單點修改操作換成了區間修改罷了

要注意的是這裡不存在負值的情況

因此在上傳操作時轉移沒那麼複雜,只用判斷\(maxl\)是否等於\(sum\)

若等於,說明左兒子中房間全為空,直接全部加上,再加上右兒子的\(maxl\)

若不等於,則為左兒子的\(maxl\)

\(maxr\)也同理

同時也要注意這裡的查詢查的是滿足長度為\(x\)的最左的端點

因此在查詢時要滿足"能左則左"

核心**:

void pushup(int node)

else

if(tree[rson].maxx==tree[rson].sum)

else

tree[node].maxx = max(tree[lson].rmax+tree[rson].lmax,max(tree[lson].maxx,tree[rson].maxx));

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

build(lson,l,mid);

build(rson,mid+1,r);

}void pushdown(int node)

if(tree[node].lazy==2)

tree[node].lazy = 0;

}void change(int node,int l,int r,int x,int y,int opt)

pushdown(node);

if(x<=mid) change(lson,l,mid,x,y,opt);

if(y>mid) change(rson,mid+1,r,x,y,opt);

pushup(node);

}int query(int node,int l,int r,int x)

else if(tree[lson].rmax+tree[rson].lmax>=x)

else return query(rson,mid+1,r,x);//否則查右邊

}}

p5459 [bjoi2016]迴轉壽司cf915e physical education lessons\(now ~ loading...\)

p5490 【模板】掃瞄線

p1502 視窗的星星

\(now ~ loading...\)

線段樹 01 線段樹基礎

物理上 public class segmenttree public int getsize public e get int index 返回完全二叉樹的陣列表示中,乙個索引所表示的元素的左孩子節點的索引 private int leftchild int index 返回完全二叉樹的陣列表示中...

線段樹 基礎

d 基礎 time limit 1000msmemory limit 32768kb64bit io format i64d i64u submit status description c國的死對頭a國這段時間正在進行軍事演習,所以c國間諜頭子derek和他手下tidy又開始忙乎了。a國在海岸線沿...

線段樹基礎

寫得不錯啊。前段時間寫了篇 搞懂樹狀陣列 如果說樹狀陣列是優雅的,那麼線段樹就是萬能的。有句話就叫 樹狀陣列能做的線段樹都能做,但是樹狀陣列能做的堅決用樹狀陣列!因為線段樹本來的內容狠豐富的,主要有單點跟新 區間跟新,最值詢問 區間詢問 反正就是對於區間進行的動態跟新詢問都能較高效的完成。對於初學者...