一区二区三区三上|欧美在线视频五区|国产午夜无码在线观看视频|亚洲国产裸体网站|无码成年人影视|亚洲AV亚洲AV|成人开心激情五月|欧美性爱内射视频|超碰人人干人人上|一区二区无码三区亚洲人区久久精品

0
  • 聊天消息
  • 系統(tǒng)消息
  • 評論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學(xué)習(xí)在線課程
  • 觀看技術(shù)視頻
  • 寫文章/發(fā)帖/加入社區(qū)
會(huì)員中心
創(chuàng)作中心

完善資料讓更多小伙伴認(rèn)識(shí)你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

樹狀數(shù)組可以很簡單

算法與數(shù)據(jù)結(jié)構(gòu) ? 來源:小K算法 ? 作者:小K ? 2022-06-21 09:27 ? 次閱讀
加入交流群
微信小助手二維碼

掃碼添加小助手

加入工程師交流群

01 故事起源有N個(gè)數(shù)排列成一排,如何快速進(jìn)行區(qū)間修改與求和呢? a24dcbdc-f100-11ec-ba43-dac502259ad0.jpg ? ?02 分析首先最容易想到的方法就是先求出前綴和sum[i],然后區(qū)間[a,b]的和就可以直接通過sum[b]-sum[a-1]得到。 a261e932-f100-11ec-ba43-dac502259ad0.jpg ?但如果要對數(shù)組進(jìn)行修改,就會(huì)有一些問題。比如對a[3]加1,則下面對應(yīng)的sum[3],sum[4],sum[5]都需要進(jìn)行修改,這個(gè)效率就很低了。 a2825ed8-f100-11ec-ba43-dac502259ad0.jpg ?原因在于sum[i]是前面區(qū)間[1,i]中所有元素的和,所以修改任何一個(gè)元素,則后面的sum[i]都得重新計(jì)算。 那能不能找到一種間斷式的前綴和呢,只需要統(tǒng)計(jì)前面區(qū)間中的部分元素。這樣在修改某個(gè)a[i]的時(shí)候就不會(huì)影響后面的所有sum[i]。 a2952c3e-f100-11ec-ba43-dac502259ad0.jpg ?其實(shí)就是要找到這樣的一種映射關(guān)系,既能統(tǒng)計(jì)出前綴和,還可以提高修改的效率。sum[i]以前是統(tǒng)計(jì)區(qū)間[1,i]所有的i個(gè)元素,而現(xiàn)在是統(tǒng)計(jì)區(qū)間[1,i]中的k個(gè)元素。 a2a7f59e-f100-11ec-ba43-dac502259ad0.jpg ?樹狀數(shù)組其實(shí)就是這樣的一種映射。 03 定義樹狀數(shù)組是按下面這種對應(yīng)關(guān)系來計(jì)算前面若干元素的和,但直接看可能還看不出來規(guī)律。 a2c1f958-f100-11ec-ba43-dac502259ad0.jpg ?先把元素的下標(biāo)1、2、3...轉(zhuǎn)成二進(jìn)制。 a2d304dc-f100-11ec-ba43-dac502259ad0.jpg ?再把每個(gè)二進(jìn)制數(shù),從右向左,截取到第一個(gè)1的位置。截取的二進(jìn)制數(shù)也會(huì)對應(yīng)一個(gè)十進(jìn)制數(shù)。 a2f8c938-f100-11ec-ba43-dac502259ad0.jpg ?比如12對應(yīng)的二進(jìn)制數(shù)為1100,截取的二進(jìn)制數(shù)為100,而100轉(zhuǎn)為十進(jìn)制為4。所以我們可以定義這樣一種運(yùn)算,lowbit(12)=4。 a30c0b6a-f100-11ec-ba43-dac502259ad0.jpg ? ?那這個(gè)lowbit要如何快速計(jì)算呢? 計(jì)算機(jī)原理中,首先我們知道有原碼,反碼,補(bǔ)碼。最高位為符號(hào)位,0為正數(shù),1為負(fù)數(shù)。正數(shù)的三碼相同,負(fù)數(shù)的反碼是符號(hào)位不變,其余位取反,而補(bǔ)碼則是反碼加1。在計(jì)算機(jī)中負(fù)數(shù)是以補(bǔ)碼的方式存儲(chǔ)的。 然后再看下面的12和-12,補(bǔ)碼進(jìn)行位與操作時(shí),就正好是lowbit運(yùn)算。 a319c872-f100-11ec-ba43-dac502259ad0.jpg代碼實(shí)現(xiàn):

			intlowbit(intx){ returnx&-x; }
			把上面的對應(yīng)位置的lowbit都計(jì)算出來再觀察,可以發(fā)現(xiàn)lowbit的數(shù)值正好就是sum[i]統(tǒng)計(jì)的元素個(gè)數(shù)。
			a32bb028-f100-11ec-ba43-dac502259ad0.jpg
			?總結(jié)一般的規(guī)律如下: sum[i]等于區(qū)間[i-lowbit(i)+1,i]中所有元素的和。也就是從位置i開始,往前數(shù)lowbit(i)個(gè)元素,加起來就是sum[i]。
			a3411f4e-f100-11ec-ba43-dac502259ad0.jpg
			?
									?04
									規(guī)律lowbit(i)對應(yīng)的數(shù)一定是1,2,4...,因?yàn)榻厝〉亩M(jìn)制為1000...。根據(jù)lowbit(i)可以先對sum[i]進(jìn)行分層。
			a3490eca-f100-11ec-ba43-dac502259ad0.jpg
			?而sum[i]元素也有一種包含關(guān)系,再把包含關(guān)系提上來。
			a35a2ca0-f100-11ec-ba43-dac502259ad0.jpg
			?sum[i]就是前面連續(xù)的lowbit(i)個(gè)元素的和,直接展開更清晰。紅色矩形就是下面覆蓋的藍(lán)色小方塊的和。
			a3837a74-f100-11ec-ba43-dac502259ad0.jpg
			?紅色是sum數(shù)組,藍(lán)色是a數(shù)組,再觀察下標(biāo)之間的關(guān)系。
			a38ebf2e-f100-11ec-ba43-dac502259ad0.jpg
			?
									?05
									單點(diǎn)修改例如修改a[2],因?yàn)閟um[2],sum[4]都包含了a[2],所以對應(yīng)都要修改。
			a3a7ffe8-f100-11ec-ba43-dac502259ad0.jpg
			?如果修改a[3],因?yàn)閟um[3],sum[4]都包含了a[3],所以對應(yīng)都要修改。
			a3c182ba-f100-11ec-ba43-dac502259ad0.jpg
			?觀察發(fā)現(xiàn),修改一個(gè)元素a[i]時(shí),sum[i]是一層一層的向上進(jìn)行修改,上一層的下標(biāo)正好是當(dāng)前層的下標(biāo)i加上lowbit(i)。
			代碼實(shí)現(xiàn):

			voidadd(intindex,intx){ while(index<=?n)?{ ????????sum[index]?+=?x; ????????index?+=?lowbit(index); ????} }
			?
									?06
									區(qū)間查詢例如查詢區(qū)間[1,5],需要統(tǒng)計(jì)sum[5],sum[4]。
			a3cd0914-f100-11ec-ba43-dac502259ad0.jpg
			?如果查詢區(qū)間[1,3],需要統(tǒng)計(jì)sum[3],sum[2]。
			a3e30a5c-f100-11ec-ba43-dac502259ad0.jpg
			?觀察發(fā)現(xiàn),查詢區(qū)間[1,i]的前綴和時(shí),是一段一段往前查詢的,下一段的下標(biāo)正好是當(dāng)前段的下標(biāo)i減去lowbit(i)。
			代碼實(shí)現(xiàn):

			intquery(intindex){ intret=0; while(index>0){ ret+=sum[index]; index-=lowbit(index); } returnret; }
			如此,就可以輕松搞定單點(diǎn)修改及區(qū)間查詢了,但最開始的問題是區(qū)間修改,這個(gè)又該如何實(shí)現(xiàn)呢?
			
									07
									區(qū)間修改首先得引入一個(gè)差分?jǐn)?shù)組d[i],d[i]=a[i]-a[i-1]。
			a3f74436-f100-11ec-ba43-dac502259ad0.jpg
			?對數(shù)組d[i]計(jì)算前綴和,又可以還原為原數(shù)組元素a[i]。
			a4071870-f100-11ec-ba43-dac502259ad0.jpg
			?通過公式替換,原數(shù)組的前綴和sum[i]也可以通過d[i]來得到。
			a419f81e-f100-11ec-ba43-dac502259ad0.jpg
			?展開來看就是這樣。
			a4396c4e-f100-11ec-ba43-dac502259ad0.jpg
			?通過觀察,可以對上面公式作如下變形。其中最關(guān)鍵的是sigma(d[j])和sigma(d[j]*j)。
			a44863f2-f100-11ec-ba43-dac502259ad0.jpg
			?如果維護(hù)d[i]和d[i]*i兩個(gè)數(shù)組的前綴和,就可以快速得到sum[k]。
			a456e594-f100-11ec-ba43-dac502259ad0.jpg
			?當(dāng)對區(qū)間[3,5]增加2時(shí),因?yàn)閐[i]是差分?jǐn)?shù)組,所以只需要對d[3]增加2,對d[6]減去2即可。同理e[i]數(shù)組,只需要e[3]增加2*3,對e[6]減去2*6。
			a475818e-f100-11ec-ba43-dac502259ad0.jpg
			?一般規(guī)律如下:
			a48245cc-f100-11ec-ba43-dac502259ad0.jpg代碼實(shí)現(xiàn):

			#defineLLlonglong //單個(gè)修改 voidadd(LL*sum,LLindex,LLx){ while(index<=?n)?{ ????????sum[index]?+=?x; ????????index?+=?lowbit(index); ????} } //區(qū)間修改 voidrange_add(LLleft,LLright,LLx){ right++; add(sum1,left,x); add(sum1,right,-x); add(sum2,left,x*left); add(sum2,right,-x*right); }
			
									08
									區(qū)間查詢代碼實(shí)現(xiàn):

			//單個(gè)查詢 LLquery(constLL*sum,LLindex){ LLret=0; while(index>0){ ret+=sum[index]; index-=lowbit(index); } returnret; } //區(qū)間查詢 LLrange_query(LLleft,LLright){ left--; LLsumA=(left+1)*query(sum1,left)-query(sum2,left); LLsumB=(right+1)*query(sum1,right)-query(sum2,right); returnsumB-sumA; }
			
									09
									總結(jié)樹狀數(shù)組主要應(yīng)用于區(qū)間操作,相比起線段樹來說,代碼實(shí)現(xiàn)簡單太多了,而且效率也很高,非常值得研究掌握。
			
			審核編輯 :李倩

聲明:本文內(nèi)容及配圖由入駐作者撰寫或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點(diǎn)僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場。文章及其配圖僅供工程師學(xué)習(xí)之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問題,請聯(lián)系本站處理。 舉報(bào)投訴
  • 代碼
    +關(guān)注

    關(guān)注

    30

    文章

    4900

    瀏覽量

    70780
  • 數(shù)組
    +關(guān)注

    關(guān)注

    1

    文章

    420

    瀏覽量

    26564

原文標(biāo)題:原來樹狀數(shù)組可以這么簡單?

文章出處:【微信號(hào):TheAlgorithm,微信公眾號(hào):算法與數(shù)據(jù)結(jié)構(gòu)】歡迎添加關(guān)注!文章轉(zhuǎn)載請注明出處。

收藏 人收藏
加入交流群
微信小助手二維碼

掃碼添加小助手

加入工程師交流群

    評論

    相關(guān)推薦
    熱點(diǎn)推薦

    如何使用閃存來保存 CYBT-343026 中的數(shù)組等數(shù)據(jù)?

    您好,我正在嘗試使用 CYBT-343026 構(gòu)建一塊電路板。 我想將數(shù)據(jù)存儲(chǔ)在一個(gè)簡單數(shù)組中。T 即使斷電,數(shù)據(jù)也應(yīng)該保留。我可以使用EEPROM,但由于數(shù)據(jù)非常簡單,所以我想使用
    發(fā)表于 06-25 06:33

    看完這篇,SPI其實(shí)也很簡單嘛(可下載)

    首先我們來簡單介紹一下SPI,SPI是串行外設(shè)接口(SerialPeripheralInterface)簡單來講就是它一種高速的,全雙工,同步的通信總線被各種總線搞的暈頭轉(zhuǎn)向的人來說就會(huì)問了
    發(fā)表于 03-26 14:29 ?2次下載

    stm32 DMA串口接收到數(shù)組數(shù)組元素順序錯(cuò)亂怎么解決?

    配置DMA循環(huán)模式,使用HAL_UART_Receive_DMA(&huart1,buffer,4)函數(shù)將串口數(shù)據(jù)循環(huán)發(fā)送到4個(gè)元素的buffer數(shù)組內(nèi),上位機(jī)20ms發(fā)送一次
    發(fā)表于 03-12 08:02

    給uint32_t數(shù)組填充整型值,除使用循環(huán)賦值外有沒有c庫函數(shù)可以實(shí)現(xiàn)?

    給uint32_t數(shù)組填充整型值,除使用循環(huán)賦值外有沒有c庫函數(shù)可以實(shí)現(xiàn)
    發(fā)表于 03-07 17:05

    字符串與字符數(shù)組的區(qū)別

    在編程語言中,字符串和字符數(shù)組是兩種基本的數(shù)據(jù)結(jié)構(gòu),它們都用于存儲(chǔ)和處理文本數(shù)據(jù)。盡管它們在功能上有一定的重疊,但在內(nèi)部表示、操作方式和使用場景上存在顯著差異。 1. 內(nèi)部表示 字符串 字符串在
    的頭像 發(fā)表于 01-07 15:29 ?1146次閱讀

    數(shù)組的下標(biāo)為什么可以是負(fù)數(shù)

    最近有同學(xué)發(fā)來這樣一段代碼,并提出一個(gè)問題,數(shù)組的下標(biāo)為什么可以是負(fù)數(shù)? ? ? #include int main(){ const char *s = "helloworld"; const
    的頭像 發(fā)表于 12-20 11:18 ?508次閱讀

    數(shù)組名之間可以直接賦值嗎

    數(shù)組之間的賦值能不能直接使用等于號(hào)?比如這樣的代碼。 int main(){ int a[5] = {1, 2, 3, 4, 5}; int b[5] = {0}; b = a
    的頭像 發(fā)表于 11-26 11:23 ?634次閱讀

    指針數(shù)組和二維數(shù)組有沒有區(qū)別

    指針數(shù)組和二維數(shù)組有沒有區(qū)別?比如這樣的兩個(gè)代碼。 int main(){ char *s1[] = { "hello", "world", "total" }; char s2[][6
    的頭像 發(fā)表于 11-24 11:12 ?548次閱讀

    C語言數(shù)組應(yīng)用計(jì)算機(jī)導(dǎo)論A第6講:數(shù)組

    C語言數(shù)組應(yīng)用計(jì)算機(jī)導(dǎo)論A第6講:數(shù)組
    發(fā)表于 11-20 15:33 ?1次下載

    解讀版|Air780E軟件中C語言內(nèi)存數(shù)組的神秘面紗!

    今天我們來揭開Air780E 軟件中 C 語言內(nèi)存數(shù)組的神秘面紗,希望有所收獲。
    的頭像 發(fā)表于 11-17 10:00 ?650次閱讀
    解讀版|Air780E軟件中C語言內(nèi)存<b class='flag-5'>數(shù)組</b>的神秘面紗!

    異形創(chuàng)意LED顯示屏定制之智慧樹狀LED喇叭屏助力文旅新征程

    智慧樹狀LED喇叭屏融合科技與藝術(shù),成文旅新星,提供沉浸式視聽盛宴,可智能互動(dòng),推動(dòng)文旅產(chǎn)業(yè)升級,注入新活力與靈感。
    的頭像 發(fā)表于 11-14 16:00 ?655次閱讀
    異形創(chuàng)意LED顯示屏定制之智慧<b class='flag-5'>樹狀</b>LED喇叭屏助力文旅新征程

    突破局限,芯知所向,芯片采購可以很簡單

    芯片
    芯廣場
    發(fā)布于 :2024年09月13日 17:34:18

    labview字符串數(shù)組轉(zhuǎn)化為數(shù)值數(shù)組

    在LabVIEW中,將字符串數(shù)組轉(zhuǎn)換為數(shù)值數(shù)組是一項(xiàng)常見的任務(wù),尤其是在處理數(shù)據(jù)采集、信號(hào)處理或用戶輸入時(shí)。 1. 理解LabVIEW的數(shù)據(jù)類型 在開始之前,了解LabVIEW中的數(shù)據(jù)類型是非
    的頭像 發(fā)表于 09-04 17:47 ?5690次閱讀

    用OPA129搭了一個(gè)很簡單的正向放大電路,電路不工作的原因?

    用OPA129搭了一個(gè)很簡單的正向放大電路,正負(fù)12V供電,輸入1mV-100mV的直流信號(hào),但是電路不工作,輸出端是10V左右。各位幫分析一下問題所在。謝謝。
    發(fā)表于 08-21 06:25

    面試???1:函數(shù)指針與指針函數(shù)、數(shù)組指針與指針數(shù)組

    在嵌入式開發(fā)領(lǐng)域,函數(shù)指針、指針函數(shù)、數(shù)組指針和指針數(shù)組是一些非常重要但又容易混淆的概念。理解它們的特性和應(yīng)用場景,對于提升嵌入式程序的效率和質(zhì)量至關(guān)重要。一、指針函數(shù)與函數(shù)指針指針函數(shù):定義:指針
    的頭像 發(fā)表于 08-10 08:11 ?1464次閱讀
    面試常考+1:函數(shù)指針與指針函數(shù)、<b class='flag-5'>數(shù)組</b>指針與指針<b class='flag-5'>數(shù)組</b>