靜謐的夜最適合刷演算法題了。刷著刷著發現了乙個好玩的資料結構叫做線段樹,據說是演算法競賽的常客哦,於是就自己寫乙個簡單的玩玩。
我用它來主要是為了快速找到陣列某區間內的數字和,並且在修改陣列某幾個元素之後再次找區間內的數字和。可想而知,我有兩個需求:求和,修改。
正常情況下,因為我們並不想給陣列排序,那麼,我們可以用o(1)的複雜度進行修改,用o(n)的複雜度遍歷區間來實現求和。但是,當我們需要頻繁進行求和的操作時,看起來很美的o(n)就變成了牆上的蚊子血,再也不是當初的紅玫瑰了,於是,我們只能優化它。
我選擇了線段樹,典型的空間換時間。我用陣列實現了二叉的線段樹,用了4倍的額外空間。這顆二叉樹的葉子節點是原始陣列的各個元素,非葉子節點儲存的為某段區間的和,一直到根節點逐步合併區間,根節點正好就是原始陣列從頭到尾的最大區間的元素和,具體的可以看看**,個人覺得**比文字更直觀哈哈。這樣的處理將求和操作變成了o(logn),而相應的修改操作也增加到了o(logn),兩個對數級別往往總是要好過乙個常數的和乙個線性的,不是麼?
talk is cheap. show me the code.
首先是構建線段樹,明白原理之後就像二叉樹一樣直接遞迴著搞就好啦:
type segmenttree struct
//初始化線段樹,至於為什麼需要4倍空間,只要咱們理解了二叉樹就一目了然了,線段樹每個節點儲存的就是某一段的區間和
func
newsegmenttree
(num [
]int
)*segmenttree
tree :=
make([
]int,4
*countnum)
if countnum >
0 leftchild :=
leftchild
(index)
rightchild :=
rightchild
(index)
mid := left +
((right - left)
>>1)
buildtree
(leftchild, left, mid)
buildtree
(rightchild, mid+
1, right)
tree[index]
= tree[leftchild]
+ tree[rightchild]
}buildtree(0
,0, countnum-1)
}return
&segmenttree
}
然後就是求和操作了,我們把各個區間的和分別儲存好了,本質上就變成了二叉樹上找常數個節點,所以當然是o(logn)了:
//求和操作,只需要通過遞迴來找到最近的區間和就好
func
(st *segmenttree)
sumrange
(start, end int
)int
leftchild :=
leftchild
(index)
rightchild :=
rightchild
(index)
mid := left +
((right - left)
>>1)
if start >= mid+
1else
if end <= mid
return
sum(leftchild, left, mid, start, mid)
+sum
(rightchild, mid+
1, right, mid+
1, end)
}return
sum(0,
0,len(st.data)-1
, start, end)
}
修改操作,好記性不如爛筆頭,用筆畫畫就可以:
//修改操作,遞迴找到葉子節點改掉索引對應的值,然後回溯的過程改掉包含索引的所有區間的和
func
(st *segmenttree)
update
(i int
, value int
) st.data[i]
= value
var up func
(int
,int
,int
) up =
func
(index, left, right int
) leftchild :=
leftchild
(index)
rightchild :=
rightchild
(index)
mid := left +
((right - left)
>>1)
if i >= mid+
1else
if i <= mid
st.tree[index]
= st.tree[leftchild]
+ st.tree[rightchild]}up
(0,0
, countnum-1)
}func
leftchild
(i int
)int
func
rightchild
(i int
)int
新手的**總是有很大的優化空間的,走過路過的大爺們要不吝賜教哦。
當然了,這僅僅只是乙個簡單的線段樹,只能解決我的小需求。還有更多的方案,比如用鍊錶來構建樹肯定要更靈活,而且線段樹並不僅僅用來求和,可以實現更多面向區間的操作,更好玩的是可以懶惰更新,每次修改不著急重新構建整棵樹,可以一點一點地來,這樣更加優化了效能。大家如果對線段樹感興趣的話,查資料去吧~o( ̄︶ ̄)o
演算法夢想家,來跟我一起玩演算法,玩**,聊聊文學創作,咱們一起天馬行空!
第一場雪 杭州
上周五杭州還熱得要命,週六就開始下雨凍人。前兩天楓葉還火紅得溢著秋意,今天就雪壓青枝了。這是我見過的第一場雪,也是今年杭州的第一場雪。以前去北方都是夏天,所以導致都沒見過雪。想起以前的同桌邀請我過去哈爾濱觀賞冰雕,我心裡有點惴惴,怕自己去了成了被觀賞的就慘了。發幾張 早上起來的時候是很小的顆粒狀。走...
暑期第一場題解
此題,emmmm,有毒,很容易出現各種bug,還是自己菜,不能動不動就覺得是資料有問題,此題肯定要用字串,模擬的題,有點長 蒟蒻瑟瑟發抖 不過不難理解,仔細看看就明白了,主要是細節方面的處理 include include include includeusing namespace std int...
暑期集訓第一場
找規律,當n 3 0的時候,ans pow n 3,3 當n 4 0的時候,就是pow n 2,2 n 4。include include define ll long long using namespace std ll t,n intmain else if n 4 0 else 題目中說了不...