国产精品久久久aaaa,日日干夜夜操天天插,亚洲乱熟女香蕉一区二区三区少妇,99精品国产高清一区二区三区,国产成人精品一区二区色戒,久久久国产精品成人免费,亚洲精品毛片久久久久,99久久婷婷国产综合精品电影,国产一区二区三区任你鲁

0
  • 聊天消息
  • 系統消息
  • 評論與回復
登錄后你可以
  • 下載海量資料
  • 學習在線課程
  • 觀看技術視頻
  • 寫文章/發帖/加入社區
會員中心
創作中心

完善資料讓更多小伙伴認識你,還能領取20積分哦,立即完善>

3天內不再提示

樹狀數組可以很簡單

算法與數據結構 ? 來源:小K算法 ? 作者:小K ? 2022-06-21 09:27 ? 次閱讀
加入交流群
微信小助手二維碼

掃碼添加小助手

加入工程師交流群

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

			intlowbit(intx){ returnx&-x; }
			把上面的對應位置的lowbit都計算出來再觀察,可以發現lowbit的數值正好就是sum[i]統計的元素個數。
			a32bb028-f100-11ec-ba43-dac502259ad0.jpg
			?總結一般的規律如下: sum[i]等于區間[i-lowbit(i)+1,i]中所有元素的和。也就是從位置i開始,往前數lowbit(i)個元素,加起來就是sum[i]。
			a3411f4e-f100-11ec-ba43-dac502259ad0.jpg
			?
									?04
									規律lowbit(i)對應的數一定是1,2,4...,因為截取的二進制為1000...。根據lowbit(i)可以先對sum[i]進行分層。
			a3490eca-f100-11ec-ba43-dac502259ad0.jpg
			?而sum[i]元素也有一種包含關系,再把包含關系提上來。
			a35a2ca0-f100-11ec-ba43-dac502259ad0.jpg
			?sum[i]就是前面連續的lowbit(i)個元素的和,直接展開更清晰。紅色矩形就是下面覆蓋的藍色小方塊的和。
			a3837a74-f100-11ec-ba43-dac502259ad0.jpg
			?紅色是sum數組,藍色是a數組,再觀察下標之間的關系。
			a38ebf2e-f100-11ec-ba43-dac502259ad0.jpg
			?
									?05
									單點修改例如修改a[2],因為sum[2],sum[4]都包含了a[2],所以對應都要修改。
			a3a7ffe8-f100-11ec-ba43-dac502259ad0.jpg
			?如果修改a[3],因為sum[3],sum[4]都包含了a[3],所以對應都要修改。
			a3c182ba-f100-11ec-ba43-dac502259ad0.jpg
			?觀察發現,修改一個元素a[i]時,sum[i]是一層一層的向上進行修改,上一層的下標正好是當前層的下標i加上lowbit(i)。
			代碼實現:

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

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

			#defineLLlonglong //單個修改 voidadd(LL*sum,LLindex,LLx){ while(index<=?n)?{ ????????sum[index]?+=?x; ????????index?+=?lowbit(index); ????} } //區間修改 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
									區間查詢代碼實現:

			//單個查詢 LLquery(constLL*sum,LLindex){ LLret=0; while(index>0){ ret+=sum[index]; index-=lowbit(index); } returnret; } //區間查詢 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
									總結樹狀數組主要應用于區間操作,相比起線段樹來說,代碼實現簡單太多了,而且效率也很高,非常值得研究掌握。
			
			審核編輯 :李倩

聲明:本文內容及配圖由入駐作者撰寫或者入駐合作網站授權轉載。文章觀點僅代表作者本人,不代表電子發燒友網立場。文章及其配圖僅供工程師學習之用,如有內容侵權或者其他違規問題,請聯系本站處理。 舉報投訴
  • 代碼
    +關注

    關注

    30

    文章

    4968

    瀏覽量

    73970
  • 數組
    +關注

    關注

    1

    文章

    420

    瀏覽量

    27360

原文標題:原來樹狀數組可以這么簡單?

文章出處:【微信號:TheAlgorithm,微信公眾號:算法與數據結構】歡迎添加關注!文章轉載請注明出處。

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

掃碼添加小助手

加入工程師交流群

    評論

    相關推薦
    熱點推薦

    RT-Thread Vector軟件包:嵌入式開發的動態數組容器 | 技術集結

    RT-Thread Vector軟件包:嵌入式開發的動態數組容器 | 技術集結
    的頭像 發表于 01-25 09:33 ?5379次閱讀
    RT-Thread Vector軟件包:嵌入式開發的動態<b class='flag-5'>數組</b>容器 | 技術集結

    利用arm-DSP庫進行FFT的計算

    電力系統中往往摻雜諧波,而FFT可以將諧波檢測出來,具有較大的實用價值。今天主要講一下在STM32中如何利用dsp庫進行快速傅里葉計算,從而得出信號的頻譜幅值以及相位。 一、Matlab簡單搭建1.
    發表于 01-21 08:19

    數組的初體驗

    程序中也需要容器,只不過該容器有點特殊,它在程序中是一塊連續的,大小固定并且里面的數據類型一致的內存空間,它還有個好聽的名字叫數組。可以數組理解為大小固定,所放物品為同類的一個購物袋,在該購 物
    發表于 11-25 08:06

    二維數組介紹

    大家不要認為二維數組在內存中就是按行、列這樣二維存儲的,實際上,不管二維、三維數組… 都是編譯器的語法糖。 存儲上和一維數組沒有本質區別,舉個例子: int array[3][3
    發表于 11-25 07:42

    SGTools--動畫控件--屏幕實現動畫顯示 就是這么簡單

    詳細步驟可以觀看視頻, 實現動畫很簡單,提前準備好gif文件和一個張背景圖 使用SGTools工具,就可以制作動畫界面啦 視頻中屏幕型號是7寸 HMT070ATA-9C
    發表于 09-16 10:29

    數組程序無法運行怎么解決?

    主控是103,程序中定義一個const類型 128k只讀數組,放在flash上,程序無法運行,堆棧都初始化不了,在keil編譯下正常,在rtthread studio下編譯無法運行,求教 是內存管理的問題嗎
    發表于 09-15 06:21

    CUBEIDE調試過程中,如何將數組仲的數據拷貝到電腦?

    請問,有什么辦法可以在CUBEIDE 調試過程中,將數組的數據拷貝到電腦上去?
    發表于 09-09 07:20

    如何使用閃存來保存 CYBT-343026 中的數組等數據?

    您好,我正在嘗試使用 CYBT-343026 構建一塊電路板。 我想將數據存儲在一個簡單數組中。T 即使斷電,數據也應該保留。我可以使用EEPROM,但由于數據非常簡單,所以我想使用
    發表于 06-25 06:33

    二維數組指定條件刪除指定行,請教

    數組1的第一列進行條件判斷,如果小于20,刪除所在行,最終需要得到數組2
    發表于 05-13 08:11

    PCB設計仿真,“縫合電容”我怎么可能不知道

    說到“縫合電容”,雖然我已經聽你們說過800多遍了,但是還是忍不住問一個很簡單的問題:額,它到底是啥。。。
    的頭像 發表于 04-28 15:43 ?624次閱讀
    PCB設計仿真,“縫合電容”我怎么可能不知道

    可以通過并聯RGB接口連接TFT屏幕嗎?

    我正在嘗試通過并聯 RGB 接口連接 TFT 屏幕,看起來很簡單,對吧? ? 24 位 RGB 的 LPC4088 僅使用 3 個 4 字節的 DMA RAM(浪費 1 個字節) 我找不到
    發表于 04-02 06:15

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

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

    Cadence畫PCB傻瓜式教程

    資料介紹: 很簡單的介紹從原理圖到PCB的簡單設計的步驟,沒有繁瑣的介紹 純分享貼,有需要可以直接下載附件獲取完整資料! (如果內容有幫助可以關注、點贊、評論支持一下哦~)
    發表于 03-22 17:06

    stm32 DMA串口接收到數組,數組元素順序錯亂怎么解決?

    配置DMA循環模式,使用HAL_UART_Receive_DMA(&huart1,buffer,4)函數將串口數據循環發送到4個元素的buffer數組內,上位機20ms發送一次
    發表于 03-12 08:02

    給uint32_t數組填充整型值,除使用循環賦值外有沒有c庫函數可以實現?

    給uint32_t數組填充整型值,除使用循環賦值外有沒有c庫函數可以實現
    發表于 03-07 17:05