關於線段的演算法彙總

2021-07-02 14:40:40 字數 2670 閱讀 7400

基本知識:

線段樹:儲存線段的二叉排序樹,以start作為key, 同時維護樹中最大的右端點值 max

class node
經典應用:query any interval that intersect(overlap) with a given interval. 如果是查詢所有與給定線段重合的線段,則查到乙個,從樹種刪去,再查。最後再插回來。複雜度為rlgn 

區間樹:區間[l, r]的左右子樹分別為[l, (l + r) / 2], [(l + r) / 2 + 1, r],葉節點都是乙個元素的區間[a,a]。主要用於查詢區間上的屬性,比如和,最大值最小值,滿足某種條件的元素個數等。

經典應用,給定乙個陣列,需要高效的查詢任意區間的和(最大值,滿足某種條件的元素個數等)。對區間建立區間樹,然後每次查詢都是lgn的。原理是這樣,原區間的值,都都是由左右兩個子區間的值得來的,類似merge,比如求整個區間的和,可以分別求左右區間的和,然後相加。這是乙個遞迴的過程,遞迴到只有乙個元素。當區間只有乙個元素時,和、最大值等都是自己。

一些經典題目:

1. 給定一組飛機的起飛和降落時間,問同時最多幾架飛機在飛行?類似的問法,一組火車出發到達時刻表,問最多同時幾趟火車在執行?一組括號中最多幾層巢狀?

solution:經典的掃瞄線法,把線段(start, end)拆成點(time, start/end),排序,如果時間值相同,終點在前起點在後。遇到乙個起點count++,遇到乙個終點count --。

int countofairplanes(vector&airplanes) 

sort(times.begin(), times.end());

int maxnum = 0, curnum = 0;

for (auto &t : times)

return maxnum;

}

2. 給定一組線段,對線段進行merge

solution: 按起點排序,

迴圈不變式:result 是乙個merge過有序的線段列表,初始化就是第乙個線段。當前線段跟result.裡最後乙個線段比,當前線段的start肯定晚於result.back()的start, 因為之前已經按start排過序,主要看是否和其end相交:

1)如果小於等於其end,說明有相交,只需要更新上乙個選段的終點 result.back().end = max(result.back().end,  cur.end())

vectormerge(vector&intervals) );

vectoroutput(1, intervals[0]);

for(int i = 1; i < intervals.size(); i++)

return output;

}

3 給定一組不想交排好序的線段,把乙個線段插入其中,並進行必要的merge

思路1)跳過在前面的、不相交的線段:新線段起點在其終點後面

2)處理重合的,更新線段的起、終點,並且刪除原線段:重合條件:新線段終點大於等於其起點(之前已經保證了新線段起點早於其終點)

版本一:原地插入

vectorinsert(vector& intervals, interval newinterval) 

intervals.insert(i, newinterval);

return intervals;

}

版本二:用另乙個列表儲存結果

public arraylistinsert(arraylistintervals, interval newinterval) 

//overlaping intervals, just keeps a longest one

for (; i < intervals.size() && intervals.get(i).start <= newinterval.end; i++)

result.add(newinterval);

// intervals going behind

for (; i < intervals.size(); i++)

result.add(intervals.get(i));

return result;

}

4 帶顏色的刷線段問題,輸入是一系列把乙個區間刷成某種顏色的操作,(start, end, color),輸出最後的狀態

分析;和insert 線段有點像,分三個部分:

1)首先要skip前面不相交的部分,toinsert.start > intervals[i].end || toinsert.start == intervals[i].end && toinsert.color != intervals[i].color,這裡的條件稍有不同,和上乙個線段的end剛好連上,但是顏色不同,也skip。

2) merge的部分:不帶顏色的線段的merge,overlap的部分連在一起,就是保留乙個最長的線段。帶顏色的話,可能是生成1個,2個,3個,兩頭部分覆蓋,中間完全覆蓋

3)後面不相交的部分,toinsert.end < intervals[i].start || toinsert.end == intervals[i].start && toinsert.color != intervals[i]

關於線段樹

首先肯定推薦學姐部落格!炒雞優秀的學姐!主要是貼 並沒有什麼理論的講解。例題 洛谷p3372 模板 線段樹1 洛谷p3373 模板 線段樹2 線段樹支援單點查詢 單點修改 區間查詢 區間修改等操作。基本思想是二分 將線段樹節點用乙個結構體打包起來 建樹 build 1,1 n void build ...

關於內錶資料彙總的一些演算法

1.把某個字段相同行的數值型資料字段彙總 如 初始資料 fld1 fld2 fld3aa 1ab2 ba3處理後資料 fld1 fld2 fld3aa 3ba3 其中 fld1,fld2 為字元型,fld3 為數值型。要求 現在我們的要求是 把 fld1 相同的行的 fld3彙總到最前面那行 如果要...

關於線段樹基礎

必須 二分法,樹的基礎 拓展 補碼,反碼,移碼,lowbit 了解什麼是線段樹及用途 線段樹,類模板題 just a hook include include include include include using namespace std const int t 100009 struct ...