線段樹 一 區間和

2022-05-07 19:27:09 字數 2240 閱讀 4520

具體線段樹講解:(搬運)

線段樹,類似區間樹,是乙個完全二叉樹,它在各個節點儲存一條線段(陣列中的一段子陣列),主要用於高效解決連續區間的動態查詢問題,由於二叉結構的特性,它基本能保持每個操作的複雜度為o(lgn)!

性質:父親的區間是[a,b],(c=(a+b)/2)左兒子的區間是[a,c],右兒子的區間是[c+1,b],線段樹需要的空間為陣列大小的四倍

線段樹的主要操作有:

(1):線段樹的構造 void build(int node, int begin, int end);

主要思想是遞迴構造,如果當前節點記錄的區間只有乙個值,則直接賦值,否則遞迴構造左右子樹,最後回溯的時候給當前節點賦值

(2):區間查詢int query(int node, int begin, int end, int left, int right);

(其中node為當前查詢節點,begin,end為當前節點儲存的區間,left,right為此次query所要查詢的區間)

主要思想是把所要查詢的區間[a,b]劃分為線段樹上的節點,然後將這些節點代表的區間合併起來得到所需資訊

比如前面乙個圖中所示的樹,如果詢問區間是[0,2],或者詢問的區間是[3,3],不難直接找到對應的節點回答這一問題。但並不是所有的提問都這麼容易回答,比如[0,3],就沒有哪乙個節點記錄了這個區間的最小值。當然,解決方法也不難找到:把[0,2]和[3,3]兩個區間(它們在整數意義上是相連的兩個區間)的最小值「合併」起來,也就是求這兩個最小值的最小值,就能求出[0,3]範圍的最小值。同理,對於其他詢問的區間,也都可以找到若干個相連的區間,合併後可以得到詢問的區間。

(3):區間或節點的更新 及 線段樹的動態維護update (這是線段樹核心價值所在,節點中的標記域可以解決n多種問題)

動態維護需要用到標記域,延遲標記等。

a:單節點更新

b:區間更新(線段樹中最有用的)

需要用到延遲標記,每個結點新增加乙個標記,記錄這個結點是否被進行了某種修改操作(這種修改操作會影響其子結點)。對於任意區間的修改,我們先按照查詢的方式將其劃分成線段樹中的結點,然後修改這些結點的資訊,並給這些結點標上代表這種修改操作的標記。在修改和查詢的時候,如果我們到了乙個結點p,並且決定考慮其子結點,那麼我們就要看看結點p有沒有標記,如果有,就要按照標記修改其子結點的資訊,並且給子結點都標上相同的標記,同時消掉p的標記。(優點在於,不用將區間內的所有值都暴力更新,大大提高效率,因此區間更新是最優用的操作)

(1):區間最值查詢問題

(2):連續區間修改或者單節點更新的動態查詢問題

(3):多維空間的動態查詢

/*******************************

線段樹v1.0

支援區間加、區間和查詢

********************************/

#include#include#include#define n 1000010

using namespace std;

struct node

tree[n];

long long a[n];

void build_tree(int left,int right,int node)//left:當前區間左端 right:當前區間右端 node:當前節點

}void push_down(int node)//標記下放 node:當前節點

void push_up(int node)//上推 node:當前節點

void add_range(int left,int right,int node,long long value)//區間加操作 left:操作區間左端點 right:操作區間右端點 node:當前節點 value:操作值

push_down(node);

int mid=(tree[node].left+tree[node].right)>>1;

if(left<=mid) add_range(left,right,node<<1,value);

if(right>mid) add_range(left,right,node<<1|1,value);

push_up(node);

}long long query_sum(int left,int right,int node)//區間和查詢 left:查詢區間左端點 right:查詢區間右端點 node:當前節點

int main()

} return 0;

}

nyistOJ 石子合併(一) 區間DP

時間限制 1000 ms 記憶體限制 65535 kb 難度 3 描述 有n堆石子排成一排,每堆石子有一定的數量。現要將n堆石子並成為一堆。合併的過程只能每次將相鄰的兩堆石子堆成一堆,每次合併花費的代價為這兩堆石子的和,經過n 1次合併後成為一堆。求出總的代價最小值。輸入 有多組測試資料,輸入到檔案...

線段樹(2)區間修改

快速序列操作i,給出乙個n個元素的陣列a1,a2,an,你的任務是設計乙個資料結構支援一下兩種操作 set l,r,v 把al,al 1,ar的值全部修改為v v 0 query l,r 計算子串行al,al 1,ar的元素和 最小值和最大值。include include using namesp...

線段樹2(區間更新)

區間更新是指更新某個區間內的葉子節點的值,因為涉及到的葉子節點不止乙個,而葉子節點會影響其相應的非葉父節點,那麼回溯需要更新的非葉子節點也會有很多,如果一次性更新完,操作的時間複雜度肯定不是o lgn 例如當我們要更新區間 0,3 內的葉子節點時,需要更新出了葉子節點3,9外的所有其他節點。為此引入...