線段樹是一種二叉搜尋樹,與區間樹相似,它將乙個區間劃分成一些單元區間,每個單元區間對應線段樹中的乙個葉結點。效能
(**於tsinghua online judge,侵刪)
題目描述
魔術師將一疊撲克順次在桌上排成一行,全部正面朝上。之後的每一次揮一揮衣袖,都會翻轉一連串的撲克,改變它們的正反朝向。從古代傳下來的規矩,魔術師皆有師傅,他們要隨時準備回答師傅的問題。問題形如:目前從第i張撲克牌到第j張撲克牌中(包含第i和第j張撲克牌),有幾張正面朝上?
現代的魔術師都有計算機,而他們的助手你被要求學習程式設計、演算法與資料結構。現在他把這個問題交給了你,你又僱傭了一家公司為你做了前端識別系統,通過置於魔術師表演桌面上面的攝像機捕捉到的影像,識別魔術師的揮一揮,並將揮一揮以標準形式傳遞給你的程式,你的程式在每一次揮一揮之後會維護相應的資料結構來儲存魔術師的桌上牌面情況,同時會開啟乙個監聽程序對師傅提的問題進行語音識別,當然這個識別系統也是僱傭別的公司給你做的,對於每乙個問題,你要用盡量快的速度計算出答案,並通過藍芽耳機傳送給魔術師。
現在,你認為邊邊角角的手勢識別系統和語音識別系統都已經交由公司解決了,那麼核心的資料結構和問題計算必須由你自己親自編寫。
輸入第一行包含三個正整數n、m,其中n表示撲克牌的數量;
接下來共m行,每行包含乙個操作,操作分為2種:
h i j //魔術師揮一揮,改變了第i張牌到第j張牌的正反
q i j //師傅問話:截至目前,第i張到第j張牌中有多少張正面朝上
h操作和q操作的範圍均包含邊界(即第i張和第j張牌)。
對於每個操作,輸入保證1 ≤ i ≤ j ≤ n。
輸出對於每次q操作,輸出一行,包含乙個整數,表示問題的答案。
資料結構
採用線段樹儲存n張牌:
思路h操作:
從根節點開始遍歷,反轉覆蓋i到j的最高的樹(count=up-down+1-count;nopass=(!nopass)
)。
q操作:
從根節點開始遍歷,查詢覆蓋i至j最高的樹,每經過乙個節點,如果nopass=1,子節點反轉(count= up-down+1-count;nopass=(!nopass)
),該節點nopass=0;然後把覆蓋i和j的最高的樹的count相加
時間複雜度:
h操作和q操作都是往下查詢一直到剛好覆蓋[i,j]的最高的節點
對於一段連續的元素,最多只有首尾兩個元素需要查詢到最後一層(其他元素左右都有元素,所以一定可以和其中乙個組成一棵子樹);
同理,線段樹的每一層最多都只可能被訪問2個元素,總共lo
gn層;
每訪問乙個節點時間複雜度o(1),所以每次操作的時間複雜度為o(
logn
) 。
共m次操作 所以時間複雜度o(
mlogn)。
查詢和修改複雜度都為log(n)
樹狀陣列和線段樹
主要解決兩個問題 其他問題可以轉化 更新某一點的值 求區間值 時間按複雜度 logn 原陣列a 1 a 2 a n 寫成樹狀陣列c c x x lowbit x x 左開右閉 筆記 主要 const int n int tr n int lowbit int x void add int x,int...
線段樹和樹狀陣列
引入1 有n個數 n 50000 個數,m m 50000 次詢問。每次詢問區間l到r的數的和。要求輸出每一次詢問的結果.分析 1.用字首和問題進行求解 再開乙個陣列 暫且記為b n 設n個數所組成的陣列為a n b i 用來記錄從a 1 到a i 的所有數字的和 即 b 1 a 1 b 2 b 1...
線段樹和樹狀陣列
線段樹 segment tree 和樹狀陣列是兩種常用的資料結構。他們用來維護乙個區間內的操作,可以在 logn 的複雜度上進行查詢和修改。線段樹可以維護對乙個區間的查詢和修改,可以對區間進行分塊查詢,而樹狀陣列是線段樹的閹割版,經常用來區間查詢,但修改只能進行單點修改,經過改造之後可以區間修改,區...