Hihocoer 1336 - Matrix Sum 二维树状数组

题意

给我们个n*n的矩阵 有m个操作让我们
操作有两种 
Add x y v对(x,y)上的元素加v
Sum x1 y1 x2 y2 对(x1,y1)为左上角(x2,y2)为右下角的矩阵求和并mod 1e9+7
初始矩阵每个元素都是0
1 ≤ N ≤ 1000, 1 ≤ M ≤ 100000
For each Add operation: 0 ≤ x < N, 0 ≤ y < N, -1000000 ≤ value ≤ 1000000
For each Sum operation: 0 ≤ x1 ≤ x2 < N, 0 ≤ y1 ≤ y2 < N 

分析

二维树状数组
操作数量巨大 不可能承受 O(M^2) 也就是如果要是我们把操作序列保存的话
假设有10000 * 10000 一万个add一万个sum那么一个数据点就会超时
那么我们来看如果只是一维的话 求两个位置间的和我们可以用前缀和
那么二维的话 我们很难在高效的时间内求出关于这个矩阵的前缀和
我们再来看 有什么数据结构可以在logn内求的数据区间之间的和呢?
可以用树状数组或是线段数
那么树状数组只能求线性结构的
这里可以考虑二维树状数组
也就是x方向一维
y方向又是一维 
两维建立树状数组t[x][y],也就是保存(1,1)到(x,y)矩阵和
对(x1,y1)为左上角(x2,y2)为右下角的矩阵求和也就是sum(x2+1,y2+1)-sum(x2+1,y1)-sum(x1,y2+1)+sum(x1,y1) 大矩阵-小矩阵右边的和-小矩阵下面的和+小矩阵和
加一是为了满足树状数组不可以对0,0点求和 所以要全部+1操作

CODE

#include<bits/stdc++.h>
using namespace std;
const int mod = 1e9+7;
typedef long long ll;
ll a[1010][1010];
int n,m;
void add(int x,int y,int v){
    for(int i=x;i<=n;i+=i&(-i)){//lowbit操作
        for(int j=y;j<=n;j+=j&(-j)){
            a[i][j]+=v;
        }
    }
}
ll sum(int x,int y){
    ll s=0;
    for(int i=x;i>0;i-=i&(-i)){
        for(int j=y;j>0;j-=j&(-j)){
            s+=a[i][j];         
        }
    }
    return s;
}
int main()
{
    scanf("%d%d",&n,&m);
    while(m--){
        char o[5];
        scanf("%s",o);
        if(o[0]=='A'){
            int x,y,v;
            scanf("%d%d%d",&x,&y,&v);
            add(x+1,y+1,v);     
        } 
        else{
            int x1,x2,y1,y2;
            scanf("%d%d%d%d",&x1,&y1,&x2,&y2);
            printf("%lld\n",(sum(x2+1,y2+1)-sum(x2+1,y1)-sum(x1,y2+1)+sum(x1,y1)+mod)%mod); 
        }//同余 由于一个负数对正数mod取余一定是个负数 mod内的负数+mod也就是相当于mod-负数和 得到mod对这个负数和的补数 
        //这个负数对mod求余 也就是这个负数的倒数 对mod求余 
    } 
    return 0;
} 
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值