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