線段樹總結

2021-08-06 03:15:30 字數 3522 閱讀 1503

線段樹能解決哪些問題:

下面給出線段樹的幾個應用:

(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...