ACM暑假训练日记 17.8.23 多维改段求点型树状数组

来源:互联网 发布:华艺服装淘宝店 编辑:程序博客网 时间:2024/05/29 17:29

今天继续做了一下树状数组的专题,上午做了一个树状数组+二分的题目比较简单的二分,用树状数组求和进行判断,二分得到最后结果。

下午在专题里面找到俩水题,轻松A掉,虽然是水题,但是比较有代表性,是两个多维改段求点型树状数组问题

首先是一个二维的

点击打开原题链接

题意,输入n,m,一个初始为0的nxn矩阵

接着m个操作

有两种情况  C a,b,c,d

将(a,b)到(c,d)范围内的矩阵进行 0 1 翻转(若原1则0,若0,则1)

仿照一维树状数组,关键点是在改变数值的那里,SUM(a,b)后,我们要消除不在要处理矩阵外的改变,本题另一个简单之处在于数值只能是0 1,而且矩形数量不大,我们只需要每次改变都加1,之后对2取余即可,用int就能实现。要消除不必要的改变的方法就是将不应该改变的部分改变偶数次,这样的话还是原值,可看做未改变,画画图就很清楚该怎么进行清除了。对于一般的题目,当不应该改变的地方加了多少,相应的,我们就应该加去多少,以确保数值不变

只需要记住一点,对于不应改变的地方,多改变了多少,就要清除多少

AC代码:



#include<stdio.h>
#include<string.h>
#define MAX 1005
int t,n,m,x1,x2,y1,y2;
long long e[MAX][MAX];
char op;
int lowbit(int k)
{
    return k&(-k);
}
int SUM(int x,int y)
{
    int re=0;
    int yy=y;
    while(x)
    {
        y=yy;
        while(y)
        {
            re+=e[x][y];
            y-=lowbit(y);
        }
        x-=lowbit(x);
    }
    return re;
}
void ADD(int x,int y)
{
    int yy=y;
    while(x<=n+1)
    {
        y=yy;
        while(y<=n+1)
        {
            e[x][y]++;
            y+=lowbit(y);
        }
        x+=lowbit(x);
    }
}
int main()
{
    scanf("%d",&t);
    while(t--)
    {
        memset(e,0,sizeof(e));
        scanf("%d%d",&n,&m);
        while(m--)
        {
            getchar();
            scanf("%c",&op);
            if(op=='C')
            {
                scanf("%d%d%d%d",&x1,&y1,&x2,&y2);
                x1++;x2++;y1++;y2++;
                **********************************
                ADD(x2,y2);
                ADD(x2,y1-1);
                ADD(x1-1,y2);
                ADD(x1-1,y1-1);
                **********************************
            }
            else
            {
                scanf("%d%d",&x1,&y1);
                printf("%d\n",(SUM(x1,y1))%2);
            }
        }
        if(t)printf("\n");
    }
}
再一个是三维的,换换说法罢了,基本是同一个代码过
点击打开链接
题意:
类似于上面,换为三维矩阵,输入时略有不同,不多叙述。
思路同上,注意消除的地方,不过和二维很类似
AC代码:
#include<stdio.h>
#include<string.h>
using namespace std;
#define MAX 105
int e[MAX][MAX][MAX],n,m,x1,x2,y1,y2,z1,z2,op;
int lowbit(int k)
{
    return k&(-k);
}
int SUM(int x,int y,int z)
{
    int yy=y;
    int zz=z;
    int re=0;
    while(x)
    {
        y=yy;
        while(y)
        {
            z=zz;
            while(z)
            {
                re+=e[x][y][z];
                z-=lowbit(z);
            }
            y-=lowbit(y);
        }
        x-=lowbit(x);
    }
    return re;
}
void ADD(int x,int y,int z)
{
    int yy=y;
    int zz=z;
    while(x<=n+1)
    {
        y=yy;
        while(y<=n+1)
        {
            z=zz;
            while(z<=n+1)
            {
                e[x][y][z]++;
                z+=lowbit(z);
            }
            y+=lowbit(y);
        }
        x+=lowbit(x);
    }
}
int main()
{
    while(~scanf("%d%d",&n,&m))
    {
        memset(e,0,sizeof(e));
        while(m--)
        {
            scanf("%d",&op);
            if(op)
            {
                scanf("%d%d%d%d%d%d",&x1,&y1,&z1,&x2,&y2,&z2);
                ************************************
                ADD(x2+1,y2+1,z2+1);
                ADD(x1,y2+1,z2+1);
                ADD(x2+1,y1,z2+1);
                ADD(x2+1,y2+1,z1);
                ADD(x2+1,y1,z1);
                ADD(x1,y2+1,z1);
                ADD(x1,y1,z2+1);
                ADD(x1,y1,z1);
                ************************************
            }
            else
            {
                scanf("%d%d%d",&x1,&y1,&z1);
                printf("%d\n",(SUM(x1,y1,z1)%2));
            }
        }
    }
}


对比两段代码编辑的部分,规律显而易见,类似于一种全排列,虽然是俩水题,但价值还是有的,对以后处理这方面的问题很有帮助
今天收获还是不错的

 
原创粉丝点击