zoukankan      html  css  js  c++  java
  • 【bzoj3132】上帝造题的七分钟 二维树状数组区间修改区间查询

    题目描述

    “第一分钟,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操作,在单独的一行输出答案。

    样例输入

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

    样例输出

    12


    题解

    二维树状数组区间修改区间查询

    头一次知道树状数组还能实现区间修改区间查询~

    我们先考虑一维的情况:树状数组的本质是$O(log n)$维护前缀和,前缀相减可以得到区间和。

    而又有一种区间修改单点查询的方法:差分。

    设$d[i]=a[i]-a[i-1]$,那么$a[i]=(a[i]-a[i-1])+(a[i-1]-a[i-2])+...+(a[1]-a[0])=sumlimits_{i=1}^nd[i]$,于是可以按照相同的方法维护差分数组的前缀和,修改的时候直接将l加上,r+1减去即可。

    那么对于区间查询呢?我们还是引入差分的思想,则$sumlimits_{i=1}^na[i]=sumlimits_{i=1}^nsumlimits_{j=1}^id[j]=sumlimits_{j=1}^n(n+1-j)d[j]=(n+1)sumlimits_{j=1}^nd[j]-sumlimits_{j=1}^nj·d[j]$。所以维护两个树状数组,一个维护d[j]的前缀和,一个维护j*d[j]的前缀和就可以了。

    那么对于本题变成二维的呢?其实也是一样的。

    还是使用差分的方法,$a[n][m]=sumlimits_{i=1}^nsumlimits_{j=1}^md[i][j]$,$sumlimits_{i=1}^nsumlimits_{j=1}^ma[i][j]=sumlimits_{i=1}^nsumlimits_{j=1}^msumlimits_{k=1}^isumlimits_{l=1}^jd[k][l]=sumlimits_{k=1}^nsumlimits_{l=1}^m(n+1-k)(m+1-l)d[k][l]$。

    展开什么的,自己动手丰衣足食

    然后开4个树状数组即可。修改和查询时使用容斥原理拆成4段来完成。

    #include <cstdio>
    #include <algorithm>
    #define N 2055
    using namespace std;
    int n , m;
    char str[5];
    struct data
    {
    	int f[N][N];
    	void update(int x , int y , int a)
    	{
    		int i , j;
    		for(i = x ; i <= n ; i += i & -i)
    			for(j = y ; j <= m ; j += j & -j)
    				f[i][j] += a;
    	}
    	int query(int x , int y)
    	{
    		int i , j , ans = 0;
    		for(i = x ; i ; i -= i & -i)
    			for(j = y ; j ; j -= j & -j)
    				ans += f[i][j];
    		return ans;
    	}
    }A , B , C , D;
    void modify(int x , int y , int z)
    {
    	A.update(x , y , z) , B.update(x , y , x * z) , C.update(x , y , y * z) , D.update(x , y , x * y * z);
    }
    int solve(int x , int y)
    {
    	return (x + 1) * (y + 1) * A.query(x , y) - (y + 1) * B.query(x , y) - (x + 1) * C.query(x , y) + D.query(x , y);
    }
    int main()
    {
    	int x1 , y1 , x2 , y2 , z;
    	scanf("%*s%d%d" , &n , &m);
    	while(~scanf("%s%d%d%d%d" , str , &x1 , &y1 , &x2 , &y2))
    	{
    		if(str[0] == 'L')
    		{
    			scanf("%d" , &z) , x2 ++ , y2 ++ ;
    			modify(x1 , y1 , z) , modify(x2 , y1 , -z) , modify(x1 , y2 , -z) , modify(x2 , y2 , z);
    		}
    		else x1 -- , y1 -- , printf("%d
    " , solve(x1 , y1) - solve(x2 , y1) - solve(x1 , y2) + solve(x2 , y2));
    	}
    	return 0;
    }
    

     

  • 相关阅读:
    布隆过滤器
    django-redis 和 vue 实现的购物车
    富文本编辑器
    django 和 七牛云 交互
    django 提供的加密算法
    DRF mixins 的常用方法
    Python笔记5(作业)
    Python笔记5(random&sys&os模块)
    Python笔记5(collections模块)
    Python笔记5(时间模块)
  • 原文地址:https://www.cnblogs.com/GXZlegend/p/7072744.html
Copyright © 2011-2022 走看看