原理很简单,就是三维树状数组模型。理解了三维树状数组,就可以直接秒杀。但是,三维的不好理解。只能由二维的去推广咯。

二维的如下(采自某大牛,感谢,膜拜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:


相信大家已经看得很清楚了,数组 b[] 正是我们想要的结果。模式二难理解主要在于 a[] 数组的意义。这时请不要再管 a[i] 表示什么,a[i] 已经没有意义了,我们需要的是 b[i]!但模式二同样存在一个缺陷,如果要对某个区间内的元素求和,就必须对该区间内的每个位置都作一次 Getsum(i),求出所有位置的真实元素值然后累加,这样复杂度又变成 O(nlogn) 了。所以要分清两种模式的优缺点,根据题目的条件选择合适的模式,灵活应变!

顺便给出二维树状数组模式二的修改方法:

#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;
}


int
main(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");
            }
        }
    }

    return
0;
}

posted on 2011-05-10 23:28  cchun  阅读(508)  评论(0编辑  收藏  举报