1. 程式人生 > >洛谷P4514上帝造題的七分鐘&&[樹狀陣列進階]

洛谷P4514上帝造題的七分鐘&&[樹狀陣列進階]

樹狀陣列大法好

講這道題之前先講點進階內容

一維樹狀陣列的區間修改+區間求和

不會樹狀陣列入門知識的->出門左轉 不會樹狀陣列單點修改的->出門右轉 好了,現在留下的都是奆佬 我們先講一下區間修改 根據之前單點修改,區間求和的思想,發現差分陣列非常有用,那麼我們不難發現一個有趣的性質,對於差分陣列d[i],原陣列a[i],存在a[i]=k=1id[i]a[i]=\sum\limits_{k=1}^{i}d[i],自己手動模擬一下 ,d[1]=a[1]d[1]=a[1]d[2]=a[2]a[1]=d[1]+d[2]=a[2]a[

1]+a[1]d[2]=a[2]-a[1]=d[1]+d[2]=a[2]-a[1]+a[1],後面類似,所以我們求字首和就可以s[i]=k=1ia[i]=k=1ij=1kd[j]s[i]=\sum\limits_{k=1}^ia[i]=\sum\limits_{k=1}^{i}\sum\limits_{j=1}^{k}d[j] 複雜度爆表,然後我們不難發現,d[1]d[1]被累加了i次,d[2]d[2]被累加了i-1次,於是我們就可以把上面n
2n^2
的式子寫成s[i]=k=1ij=1kd[j]=k=1id[k](ik+1)=(i+1)k=1id[k]k=1id[k]ks[i]=\sum\limits_{k=1}^{i}\sum\limits_{j=1}^{k}d[j]=\sum\limits_{k=1}^{i}d[k] * (i-k+1)=(i+1) * \sum\limits_{k=1}^{i}d[k] - \sum\limits_{k=1}^{i}d[k] * k,於是我們就可以用樹狀陣列維護兩個陣列,一個是d
[i]d[i]
,另一個是d[i]id[i]*i,然後查詢的時候就套上面的式子就好了,是不是比線段樹簡單多了

二維樹狀陣列

類比一維樹狀陣列,一維樹狀陣列陣列上,字首和是每次減個lowbit的位置加起來,那麼我們放在二維上,我們可以想象為先橫著求和,再豎著求和,所以是

for (int i=x;i;i-=lowbit(i)
for (int k=y;k;k-=lowbit(k)

這樣就可以得到字首和了,但是我要求你有修改操作 類比一下一維樹狀陣列的差分性質,我們對它做一個二維差分,想一下二維字首和,i,k的二維字首和和等於s[i][k]=s[i1][k]+s[i][k1]s[i1][k1]+a[i][k]s[i][k]=s[i-1][k]+s[i][k-1]-s[i-1][k-1]+a[i][k],於是我們就類比了一下,我們使得差分陣列d[i][k]=a[i][k]a[i1][k]a[i][k1]+a[i1][k1]d[i][k]=a[i][k]-a[i-1][k]-a[i][k-1]+a[i-1][k-1],然後d[i][k]d[i][k]也存在類似於一維的性質d[i][k]=x=1iy=1kd[x][y]d[i][k]=\sum\limits_{x=1}^{i}\sum\limits_{y=1}^{k}d[x][y],手模一下就發現了,或者根據差分的過程也能得到,所以字首和就是s[i][k]=j=1il=1kx=1jy=1ld[x][y]s[i][k]=\sum\limits_{j=1}^{i}\sum\limits_{l=1}^{k}\sum\limits_{x=1}^{j}\sum\limits_{y=1}^{l}d[x][y],複雜度炸了一地啊!然後開始優化,發現d[1][1]d[1][1]用了iki * k次,d[2][2]d[2][2]用了i(k1)i*(k-1)次,所以得到對於差分數組裡的d[x][y]d[x][y]用了(ix+1)(ky+1)(i-x+1)*(k-y+1)次,化簡上面式子s[i][k]=x=1iy=1kd[x][y](ix+1)(ky+1)s[i][k]=\sum\limits_{x=1}^{i}\sum\limits_{y=1}^{k}d[x][y]*(i-x+1)*(k-y+1),還是沒辦法直接維護,繼續化簡一下? =x=1iy=1kd[x][y](ix+1)(ky+1)=\sum\limits_{x=1}^{i}\sum\limits_{y=1}^{k}d[x][y]*(i-x+1)*(k-y+1) =x=1iy=1kd[x][y](i+1)(k+1y)x=1iy=1kd[x][y]x(k+1y)=\sum\limits_{x=1}^{i}\sum\limits_{y=1}^{k}d[x][y]*(i+1)*(k+1-y)-\sum\limits_{x=1}^{i}\sum\limits_{y=1}^{k}d[x][y]*x*(k+1-y) =x=1iy=1kd[x][y](i+1)(k+1)x=1iy=1kd[x][y](i+1)yx=1iy=1kd[x][y]x(k+1)+x=1iy=1kd[x][y]xy=\sum\limits_{x=1}^{i}\sum\limits_{y=1}^{k}d[x][y]*(i+1)*(k+1)-\sum\limits_{x=1}^{i}\sum\limits_{y=1}^{k}d[x][y]*(i+1)*y-\sum\limits_{x=1}^{i}\sum\limits_{y=1}^{k}d[x][y]*x*(k+1)+\sum\limits_{x=1}^{i}\sum\limits_{y=1}^{k}d[x][y]*x*y 整理一下得到 (i+1)(k+1)x=1iy=1kd[x][y](i+1)x=1iy=1kd[x][y]y(k+1)x=1iy=1kd[x][y]x+x=1iy=1kd[x][y]xy(i+1)*(k+1)*\sum\limits_{x=1}^{i}\sum\limits_{y=1}^{k}d[x][y]-(i+1)*\sum\limits_{x=1}^{i}\sum\limits_{y=1}^{k}d[x][y]*y-(k+1)*\sum\limits_{x=1}^{i}\sum\limits_{y=1}^{k}d[x][y]*x+\sum\limits_{x=1}^{i}\sum\limits_{y=1}^{k}d[x][y]*x*y