這題一眼看去就是更新區間尋找點,典型的樹狀數組解法,但是如果用三維樹狀數組的話,會遇到一個難題,那就是怎麼分割?
我們看簡單的問題開始,對於一維的情況,將區間(a,b)進行更新,那麼就在a處加v,b+1處減v即可。
對於二維的情況,那就麻煩一點,將地區(x1,y1)到(x2,y2)進行更新,那麼就在(x1,y1)處加v,在(x2+1,y1)和(x1,y2+1)處減v,在(x2+1,y2+1)處加v即可。
那麼三維的呢?經過畫圖,我得到了結論,那就是(x1,y1,z1)加v,和(x1,y1,z1)相鄰奇數長度的點減v,這些點有(x2+1,y1,z1)、(x1,y2+1,z1)、(x1,y1,z2+1)還有(x2+1,y2+1,z2+1),剩下的就是加v了。
把三個維度不同的樹狀數組的情況和在一起,源點P加v和P相鄰奇數位置的減v,偶數位置的加v,這樣就可以快速地記下來全部的切割情況了。
My Code:
#include <iostream><br />#include <cstdio><br />#include <cstring><br />#include <cstdlib></p><p>using namespace std;</p><p>const int MAX=110;<br />int n;<br />int tree[MAX][MAX][MAX];</p><p>void add(int x,int y,int z,int v)<br />{<br />int tmp1=y;<br />int tmp2=z;<br />while(x<=n)<br />{<br />y=tmp1;<br />while(y<=n)<br />{<br />z=tmp2;<br />while(z<=n)<br />{<br />tree[x][y][z]+=v;<br />z+=z&-z;<br />}<br />y+=y&-y;<br />}<br />x+=x&-x;<br />}<br />}</p><p>int read(int x,int y,int z)<br />{<br />int tmp1=y;<br />int tmp2=z;<br />int sum=0;<br />while(x)<br />{<br />y=tmp1;<br />while(y)<br />{<br />z=tmp2;<br />while(z)<br />{<br />sum+=tree[x][y][z];<br />z-=z&-z;<br />}<br />y-=y&-y;<br />}<br />x-=x&-x;<br />}</p><p>return sum;<br />}</p><p>int main()<br />{<br />int m;<br />int x1,x2,y1,y2,z1,z2,op;</p><p>while(scanf("%d%d",&n,&m)!=EOF)<br />{<br />for(int i=1;i<=n;i++)<br />for(int j=1;j<=n;j++)<br />for(int k=1;k<=n;k++)<br />tree[i][j][k]=0;<br />for(int i=0;i<m;i++)<br />{<br />scanf("%d",&op);<br />if(op)<br />{<br />scanf("%d%d%d",&x1,&y1,&z1);<br />scanf("%d%d%d",&x2,&y2,&z2);<br />add(x1,y1,z1,1);<br />add(x2+1,y1,z1,-1);<br />add(x1,y2+1,z1,-1);<br />add(x1,y1,z2+1,-1);<br />add(x2+1,y2+1,z1,1);<br />add(x2+1,y1,z2+1,1);<br />add(x1,y2+1,z2+1,1);<br />add(x2+1,y2+1,z2+1,-1);<br />}<br />else<br />{<br />scanf("%d%d%d",&x1,&y1,&z1);<br />printf("%d/n",read(x1,y1,z1)%2);<br />}<br />}<br />}</p><p>return 0;<br />}<br />
總結:每次做題後要反思,不能做一題過一題,寧可花時間想怎麼最佳化代碼,畢竟這個對自己好處更大。做題不貴多,而貴精。