上帝造题的七分钟(二维树状数组)

本文详细介绍了基于二维差分树解决矩阵修改与查询问题的算法原理与实现过程,通过一个具体的编程实例,展示了如何利用差分树进行高效的数据更新和范围查询,特别适用于大规模数据集上的操作。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

【问题描述】

“第一分钟,X说,要有矩阵,于是便有了一个里面写满了0的n×m矩阵。
  第二分钟,L说,要能修改,于是便有了将左上角为(a,b),右下角为(c,d)的一个矩形区域内的全部数字加上一个值的操作。
  第三分钟,k说,要能查询,于是便有了求给定矩形区域内的全部数字和的操作。
  第四分钟,彩虹喵说,要基于二叉树的数据结构,于是便有了数据范围。
  第五分钟,和雪说,要有耐心,于是便有了时间限制。
  第六分钟,吃钢琴男说,要省点事,于是便有了保证运算过程中及最终结果均不超过32位有符号整数类型的表示范围的限制。
  第七分钟,这道题终于造完了,然而,造题的神牛们再也不想写这道题的程序了。”
                  ——《上帝造裸题的七分钟》
  所以这个神圣的任务就交给你了。

【输入格式】

输入数据的第一行为X n m,代表矩阵大小为n×m。
  从输入数据的第二行开始到文件尾的每一行会出现以下两种操作:
  L a b c d delta —— 代表将(a,b),(c,d)为顶点的矩形区域内的所有数字加上delta。
  k a b c d   —— 代表求(a,b),(c,d)为顶点的矩形区域内所有数字的和。
  请注意,k为小写。

【输出格式】

针对每个k操作,在单独的一行输出答案。

【输入输出样例 1】

input

X 4 4
L 1 1 3 3 2
L 2 2 4 4 1
k 2 2 3 3

output

12

数据规模

对于100%的数据,1 ≤ n ≤ 2048, 1 ≤ m ≤ 2048, 1 ≤ abs(delta) ≤ 500,操作不超过200000个,保证运算过程中及最终结果均不超过32位带符号整数类型的表示范围。

时间限制:1s

空间限制:128MB

【思路】——————

【题解】——————

 

#include<bits/stdc++.h>
using namespace std; 
int dif1[2049][2049];
int dif2[2049][2049];
int dif3[2049][2049];
int dif4[2049][2049];
int n,m;
int lowbit(int x)
{
    return x&(-x);
}
int change_dif(int dif[][2049],int a,int b,int v)
{
    int x=a,y;
    while(x<=n)
    {
        y=b;
        while(y<=n)
        {
            dif[x][y]+=v;
            y+=lowbit(y);   
        }       
        x+=lowbit(x);
    }
}
int sum_dif(int dif[][2049],int a,int b)
{
    int s=0;
    int x=a,y;
    while(x)
    {
        y=b;
        while(y)
        {
	        s+=dif[x][y];
	        y-=lowbit(y);   
	    }       
        x-=lowbit(x);
    }
    return s; 
}
void update(int a,int b,int value)//每次需要维护4个差分数组 
{
    change_dif(dif1,a,b,value);
    change_dif(dif2,a,b,-a*value);
    change_dif(dif3,a,b,-b*value);
    change_dif(dif4,a,b,a*b*value);
}
int sum_range(int x,int y)//根据刷题网站博客《信奥数学》中的公式求前缀和 
{
    int ans=0;
    ans=(x+1)*(y+1)*sum_dif(dif1,x,y)+(y+1)*sum_dif(dif2,x,y)+(x+1)*sum_dif(dif3,x,y)+sum_dif(dif4,x,y);
    return ans;
} 
int main()
{
    int tmp,u1,u2,v1,v2,value,u3,u4;
    int ans=0;
    char c;
    scanf("X %d %d",&n,&m);
    getchar(); 
    while((c=getchar())!=EOF)
    {
    	ans=0;
        if(c=='L')      
        {
            scanf("%d %d %d %d %d",&u1,&u2,&u3,&u4,&value);                 
            //调用update每次维护4个区域 
            update(u1,u2,value);
            update(u1,u4+1,-value);
            update(u3+1,u2,-value);
            update(u3+1,u4+1,value);
        }
        else if(c=='k')
        {
            scanf("%d %d %d %d",&u1,&u2,&u3,&u4);
            ans=sum_range(u3,u4)- sum_range(u1-1,u4)-sum_range(u3,u2-1)+sum_range(u1-1,u2-1);//容斥 
            printf("%d\n",ans);
        }
    }
    return 0; 
}

【拓展】——————

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值