• 二维树状数组+差分【p4514】上帝造题的七分钟


    Description

    “第一分钟,X说,要有矩阵,于是便有了一个里面写满了(0)(n imes m)矩阵。

    第二分钟,L说,要能修改,于是便有了将左上角为((a,b)),右下角为((c,d))的一个矩形区域内的全部数字加上一个值的操作。

    第三分钟,k说,要能查询,于是便有了求给定矩形区域内的全部数字和的操作。

    第四分钟,彩虹喵说,要基于二叉树的数据结构,于是便有了数据范围。

    第五分钟,和雪说,要有耐心,于是便有了时间限制。

    第六分钟,吃钢琴男说,要省点事,于是便有了保证运算过程中及最终结果均不超过32位有符号整数类型的表示范围的限制。

    第七分钟,这道题终于造完了,然而,造题的神牛们再也不想写这道题的程序了。”

    ——《上帝造裸题的七分钟》 所以这个神圣的任务就交给你了。

    Input

    输入数据的第一行为X n m,代表矩阵大小为(n imes m)
    从输入数据的第二行开始到文件尾的每一行会出现以下两种操作:

    • L a b c d delta —— 代表将((a,b),(c,d))为顶点的矩形区域内的所有数字加上delta。
    • k a b c d —— 代表求((a,b),(c,d))为顶点的矩形区域内所有数字的和。

    请注意,(k)为小写。

    Output

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

    裸的二维树状数组问题.

    二维前缀和:

    [sum[i][j]=sum[i-1][j]+sum[i][j-1]-sum[i-1][j-1]+a[i][j] ]

    考虑差分:

    [d[i][j]表示a[i][j]与a[i-1][j]+a[i][j-1]-a[i-1][j-1]的差 ]

    此时小推一下式子即可.

    区间修改,区间查询

    [sum_{i=1}^{x}sum_{j=1}^{y}sum_{k=1}^{i}sum_{h=1}^{j}d[h][k] ]

    这个时候记录每个位置的(d[h][k])出现了几次.

    所以式子变形得到.

    [sum_{i=1}^{x}sum_{j=1}^{y}d[i][j] imes (x-i+1) imes (y-j+1) ]

    然后把式子展开.就变成这个

    [(x+1) imes (y+1) imes sum_{i=1}^{x}sum_{j=1}^{y}d[i][j]-(y+1) imessum_{i=1}^{x}sum_{j=1}^{y}d[i][j] imes i -(x+1)sum_{i=1}^{x}sum_{j=1}^{y}d[i][j] imes j + sum_{i=1}^{x}sum_{j=1}^{y}d[i][j] imes i imes j ]

    然后四个树状数组数组分别维护这些东西:

    (d[i][j],d[i][j] imes i ,d[i][j] imes j,d[i][j] imes i imes j)

    代码

    #include<cstdio>
    #include<cctype>
    #define N 2050
    #define R register
    using namespace std;
    inline void in(int &x)
    {
    	int f=1;x=0;char s=getchar();
    	while(!isdigit(s)){if(s=='-')f=-1;s=getchar();}
    	while(isdigit(s)){x=x*10+s-'0';s=getchar();}
    	x*=f;
    }
    int t1[N][N],t2[N][N],t3[N][N],t4[N][N],n,m;
    #define lowbit(x) x&-x
    inline void add(int x,int y,int del)
    {
    	for(R int i=x;i<=n;i+=lowbit(i))
    		for(R int j=y;j<=m;j+=lowbit(j))
    		{
    			t1[i][j]+=del;
    			t2[i][j]+=del*x;
    			t3[i][j]+=del*y;
    			t4[i][j]+=del*x*y;
    		}
    }
    inline void ado(int xa,int ya,int xb,int yb,int z)
    {add(xa,ya,z);add(xa,yb+1,-z);add(xb+1,ya,-z);add(xb+1,yb+1,z);}
    inline int que(int x,int y)
    {
    	R int res=0;
    	for(R int i=x;i;i-=lowbit(i))
    		for(R int j=y;j;j-=lowbit(j))
    			res+=(x+1)*(y+1)*t1[i][j]-(y+1)*t2[i][j]-(x+1)*t3[i][j]+t4[i][j];
    	return res;
    }
    inline int query(int xa,int ya,int xb,int yb)
    {return que(xb,yb)-que(xb,ya-1)-que(xa-1,yb)+que(xa-1, ya-1);}
    char s[6];
    int main()
    {
    	in(n),in(m);
    	for(R int a,b,c,d,x;~scanf("%s",s+1);)
    	{
    		in(a),in(b),in(c),in(d);
    		if(s[1]=='L')in(x),ado(a,b,c,d,x);
    		else printf("%d
    ",query(a,b,c,d));
    	}
    }
    
  • 相关阅读:
    数据库访问表的问题
    UVA 10943全加和(规律)
    POJ 2594 最小路径覆盖 + 传递闭包
    phonegap入门7 capture.captureVideo 录像
    第二部分 Linux Shell高级编程技巧——第二章 Shell工具
    C#写的光模块烧写软件
    关于java的++和操作符,你真的搞明白了吗?
    MFCATL IDispatch调度接口
    c/c++函数调用约定
    HDOJ 2955 Robberies (0/1背包)
  • 原文地址:https://www.cnblogs.com/-guz/p/9839300.html
Copyright © 2020-2023  润新知