線段樹能解決哪些問題:
下面給出線段樹的幾個應用:
(1)有一列數,初始值全部為0。每次可以進行以下三種操作中的一種:
a. 給指定區間的每個數加上乙個特定值;
b.將指定區間的所有數置成乙個統一的值;
c.詢問乙個區間上的最小值、最大值、所有數的和。
給出一系列a.b.操作後,輸出c的結果。
[問題分析]
這個是典型的線段樹的應用。在每個節點上維護一下幾個變數:delta(區間增加值),same(區間被置為某個值),min(區間最小值),max(區間最大值),sum(區間和),其中delta和same屬於「延遲標記」。
(2)在所有不大於30000的自然數範圍內討論乙個問題:已知n條線段,把端點依次輸入給你,然後有m(≤30000)個詢問,每個詢問輸入乙個點,要求這個點在多少條線段上出現過。
[問題分析]
這個題目也告訴我們,有的題目儘管可以使用線段樹處理,但是如果我們能夠抓住題目的特點,就可能獲得更加優秀的演算法。
(3)某次列車途經c個城市,城市編號依次為1到c,列車上共有s個座位,鐵路局規定售出的車票只能是坐票,即車上所有的旅客都有座,售票系統是由計算機執行的,每乙個售票申請包含三個引數,分別用o、d、n表示,o為起始站,d為目的地站,n為車票張數,售票系統對該售票申請作出受理或不受理的決定,只有在從o到d的區段內列車上都有n個或n個以上的空座位時該售票申請才被受理,請你寫乙個程式,實現這個自動售票系統。
[問題分析]
(4)給乙個n*n的方格棋盤,初始時每個格仔都是白色。現在要刷m次黑色或白色的油漆。每次刷漆的區域都是乙個平行棋盤邊緣的矩形區域。
輸入n,m,以及每次刷漆的區域和顏色,輸出刷了m次之後棋盤上還有多少個棋格是白色。
[問題分析]
首先我們從簡單入手,考慮一維的問題。即對於乙個長度為n的白色線段,對它進行m次修改(每次更新某一子區域的顏色)。問最後還剩下的白色區域有多長。
對於這個問題,很容易想到建立一棵線段樹的模型。複雜度為o(mlgn)。
擴充套件到二維,需要把線段樹進行調整,即首先在橫座標上建立線段樹,它的每個節點是一棵建立在縱座標上的線段樹(即樹中有樹。稱為二維線段樹)。複雜度為o(m(logn)^2)。
4、總結
利用線段樹,我們可以高效地詢問和修改乙個數列中某個區間的資訊,並且**也不算特別複雜。
但是線段樹也是有一定的侷限性的,其中最明顯的就是數列中數的個數必須固定,即不能新增或刪除數列中的數。
線段樹的模板:
一,根據題目建樹:
const int max = 1000000+10;
struct node
tree[max*3];//要開大一點
void pushup(int o)//更新當前節點的值
void build(int o,int l,int r)
int mid = (l+r) >> 1; //找到中間節點
build(o*2 , l , mid); //遞迴建左子樹
build(o*2+1 , mid+1 , r); //遞迴建右子樹
pushup(o); //更新當前節點的值
}
二:更新某個節點的資料:(把x節點更新為y)
void update(int o,int l,int r,int x,int y) //把x節點更新為y
int mid = (l+r) / 2; //找到中間位置
if (x <= mid)
update(o*2,l,mid,x,y); //找左子樹
else
update(o*2+1,mid+1,r,x,y); //找右子樹
pushup(o); //更新當前節點
}
三,查詢某個區間的總和:(查詢x到y的和)
int querysum(int o,int l,int r,int x,int y) //查詢x到y的和
int mid = (l + r) / 2;
if (mid >= y) //全在左邊
return querysum(o*2,l,mid,x,y);
else
if (x > mid) //全在右邊
return querysum(o*2+1,mid+1,r,x,y);
else
//一半在左一半在右
return querysum(o*2,l,mid,x,mid) + querysum(o*2+1,mid+1,r,mid+1,y);
}
四:查詢某個區間的最大值和最小值(查詢x到y的最大值)
兩種寫法:
1.分別查詢
int querymax(int o,int l,int r,int x,int y)//查詢x到y的最大值
int mid = (l + r) / 2;
if (mid >= y) //全在左邊
return querymax(o*2,l,mid,x,y);
else
if (x > mid) //全在右邊
return querymax(o*2+1,mid+1,r,x,y);
else
//一半在左一半在右
return
max(querymax(o*2,l,mid,x,mid) , querymax(o*2+1,mid+1,r,mid+1,y));
}int querymin(int o,int l,int r,int x,int y)
int mid = (l + r) / 2;
if (mid >= y) //全在左邊
return querymin(o*2,l,mid,x,y);
else
if (x > mid) //全在右邊
return querymin(o*2+1,mid+1,r,x,y);
else
//一半在左一半在右
return
min(querymin(o*2,l,mid,x,mid) , querymin(o*2+1,mid+1,r,mid+1,y));
}
2.同時查詢:
需要在main()函式外定義全域性變數。
int maxx=-1;
int minn=100000010;
void query(int o,int l,int r,int u,int v)
else}}
函式執行之後minn 和maxx即為區間內的最小值和最大值。
main()函式依據題目來寫。
線段樹總結
線段樹總結 線段樹的原理就是每乙個區間都可以被分成若干個不相交連續區間 重要 線段樹維護的資料 1.自身結構的資料 比如 左兒子 右兒子的編號 2.懶惰標記 整段區間都變成乙個值 或者將要進行什麼操作 根據每次操作的型別 把操作的區間分成若干個不連續的區間 然後把操作的標記賦值給相應的區間 3.答案...
線段樹總結
線段樹的入門級 總結 線段樹是一種二叉搜尋樹,與區間樹相似,它將乙個區間劃分成一些單元區間,每個單元區間對應線段樹中的乙個葉結點。對於線段樹中的每乙個非葉子節點 a,b 它的左兒子表示的區間為 a,a b 2 右兒子表示的區間為 a b 2 1,b 因此線段樹是平衡二叉樹,最後的子節點數目為n,即整...
線段樹總結
解決的題目 對區間所對應的一些資料進行修改,查詢。基本步驟 先建樹,然後插入資料,然後更新,查詢。關鍵部分 用線段樹解題,關鍵是要想清楚每個節點要存哪些資訊以及這些資訊如何高效更新,維護,查詢。不要一更新就更新到葉子節點,那樣更新效率最壞就可能變成o n 的了。建樹的方式 1 陣列 若根節點下標為0...