【二维树状数组】POJ2155 矩阵操作

之前是学会了用二维树状数组进行单点更新、区间查询、子矩阵查询,但是如果想要“子矩阵更新”、“单点查询”呢?

是不是很奇葩,其实后者都可以由前面所学的“转化”而成




大致思路

搞懂它我还是想了很多看了很多的0.0

首先我们换道题:如果只是在一维数组上操作的话,是不是只需要在左端点+1,右端点-1,即区间更新->单点更新了。查询单点x的时候只需要把1~x的值求和,就知道被更新的次数了,即单点查询->区间查询。(这个题就是之前的“木桩涂涂看”呀)

然后回到这个二维数组上来,我们其实也是相同的操作,只是需要考虑的情况比较多,见图:


我们想要更新绿色这块儿的子矩阵,首先,最后单点查询是要看从左上角拉到单点的一个矩阵和,那么我们就去拉。我考虑了以下几种情况,以灰框所示拉出来的矩阵:


那么,希望的效果是:如果单点(即灰框的右下角)在绿色区域里,那么灰框矩阵的和必为1,相反,如果在外面,必为0.

要达到这个效果,只需要在红色标记那四个点上分别赋值(4次单点更新),值见图。(反正根据图分析就清楚了)


还有个关键点:因为是在 0 1 0 1这样更新的,如果你进行了多次更新,比如说进行了3次,那你的值应该是1,而进行了4次,即回到初始值0. 关于这种交替更新,典型的就是用“%2”!


代码

#include<iostream>
#include<bits/stdc++.h> 
using namespace std;  
int sum[1005][1005];  
int n;  
int lowbit(int x)  
{  
    return x&(-x);  
}  
int getsum(int x,int y)  
{  
    int s=0;  
    while(x>0)  
    {  
        int t=y;  
        while(t>0)
        {  
            s+=sum[x][t];  
            t-=lowbit(t);  
        }  
        x-=lowbit(x);  
    }  
    return s;
}  
void update(int x,int y,int v)  
{  
    while(x<=n)
    {  
        int t=y;  
        while(t<=n)  
        {  
            sum[x][t]+=v;  
            t+=lowbit(t);  
        }  
        x+=lowbit(x);  
    }  
}  
int main()  
{  
    int i,j,test,m,x1,y1,x2,y2,x,y;  
    char c;  
        scanf("%d%d",&n,&m);  
        for(i=0;i<m;i++)  
        {  
            getchar();//吸收回车  
            scanf("%c",&c);  
            if(c=='C')  
            {  
                scanf("%d%d%d%d",&x1,&y1,&x2,&y2);  
                update(x1,y1,1);
                update(x2+1,y1,-1);  
                update(x1,y2+1,-1); 
                update(x2+1,y2+1,1);
            }  
            else  
            {  
                scanf("%d%d",&x,&y);  
                printf("%d\n",getsum(x,y)%2);  
            }  
        }  
    return 0;  
}  

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值