原理很简单,就是三维树状数组模型。理解了三维树状数组,就可以直接秒杀。但是,三维的不好理解。只能由二维的去推广咯。
二维的如下(采自某大牛,感谢,膜拜v):
模式二:随时修改数组 a[] 中某个区间的值(O(1)),查询某个元素的值(O(logn))
在这种模式下,a[i] 已经不再表示真实的值了,只不过是一个没有意义的、用来辅助的数组。这时我们真正需要的是另一个假想的数组 b[],b[i] 才表示真实的元素值。但 c[] 数组却始终是为 a[] 数组服务的,这一点大家要明确。此时 Getsum(i) 虽然也是求 a[i] 之前的元素和,但它现在表示的是实际我要的值,也就是 b[i]。
比如现在我要对图1 中 a[] 数组中红色区域的值全部加1。当然你可以用模式一的 Modify(i) 对该区间内的每一个元素都修改一次,但如果这个区间很大,那么每次修改的复杂度就都是 O(nlogn),m 次修改就是 O(mnlogn),这在 m 和 n 很大的时候仍是不满足要求的。这时模式二便派上了用场。我只要将该区域的第一个元素 +1,最后一个元素的下一位置 -1,对每个位置 Getsum(i) 以后的值见图2:
顺便给出二维树状数组模式二的修改方法:
#include<iostream>
#define N 105
#define lowbit(x) x&(-x)
using namespace std;
int tree[N][N][N];
void add(int a,int b,int c,int n)
{
int i,j,k;
for(i=a;i<N;i+=lowbit(i))
for(j=b;j<N;j+=lowbit(j))
for(k=c;k<N;k+=lowbit(k))
{
tree[i][j][k]+=n;
}
}
int subsum(int a,int b,int c)
{
int i,j,k,sum=0;
for(i=a;i>0;i-=lowbit(i))
for(j=b;j>0;j-=lowbit(j))
for(k=c;k>0;k-=lowbit(k))
{
sum+=tree[i][j][k];
}
return sum;
}
intmain(void)
{
int i,j,k,m,n,sel,x1,y1,z1,x2,y2,z2;
int sum;
while(scanf("%d%d",&n,&m)==2)
{
for(i=0;i<N;i++)
for(j=0;j<N;j++)
for(k=0;k<N;k++)
tree[i][j][k]=0;
for(i=0;i<m;i++)
{
scanf("%d",&sel);
if(sel==1)
{
scanf("%d%d%d%d%d%d",&x1,&y1,&z1,&x2,&y2,&z2);
//cout<<"fsdf";
add(x1,y1,z1,1);
add(x2+1,y1,z1,-1);
add(x1,y2+1,z1,-1);
add(x1,y1,z2+1,-1);
add(x2+1,y2+1,z1,1);
add(x1,y2+1,z2+1,1);
add(x2+1,y1,z2+1,1);
add(x2+1,y2+1,z2+1,-1);
}
else
{
scanf("%d%d%d",&x1,&y1,&z1);
sum=subsum(x1,y1,z1);
if((sum&1)==0)
printf("0\n");
else
printf("1\n");
}
}
}
return0;
}