• [luogu] P4514 上帝造题的七分钟 (树状数组,二维差分)


    P4514 上帝造题的七分钟

    题目背景

    裸体就意味着身体。

    题目描述

    “第一分钟,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: 复制

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

    输出样例#1: 复制

    12

    说明

    对于10%的数据,1 ≤ n ≤ 16, 1 ≤ m ≤ 16, 操作不超过200个.
    对于60%的数据,1 ≤ n ≤ 512, 1 ≤ m ≤ 512.
    对于100%的数据,1 ≤ n ≤ 2048, 1 ≤ m ≤ 2048, -500 ≤ delta ≤ 500,操作不超过200000个,保证运算过程中及最终结果均不超过32位带符号整数类型的表示范围。
    by XLk



    题解

    想写二维线段树。
    然而讨论里说卡掉了空间了。
    那就硬着头皮写二维树状数组吧。
    二维树状数组教做人系列。

    对于一维的树状数组,我们知道区间加和区间求和是需要差分并维护两个树状数组的。(不会的可以去用树状数组写一下x谷的线段树模板1)
    这个对于二维树状数组同样适用。
    那么我们假设(sum[i][j])为差分数组。
    (sum[i][j]=a[i][j]-a[i-1][j]-a[i][j-1]+a[i-1][j-1])
    为什么要这么假设呢?
    因为这样我们可以发现
    对于点((x,y))的值就是
    (sum_{i=1}^xsum_{j=1}^ysum_{h=1}^isum_{k=1}^j sum[h][k])
    根据每一次的求值,我们发现以((x,y))为结尾的矩阵,每个差分数组出现的次数为
    (sum_{i=1}^xsum_{j=1}^y sum[i][j]*(x-i+1)*(y-j+1))
    是不是会发现开始变得和一维树状数组求法一样了。

    接下来让我们把这个公式拆开食用。
    (sum_{i=1}^xsum_{j=1}^y sum[i][j]*(xy+x+y+1)-sum[i][j]*i(y+1)-sum[i][j]*j(x+1)+sum[i][j]*i*j)
    发现只要维护(sum[i][j],sum[i][j]*i,sum[i][j]*j,sum[i][j]*i*j)四个树状数组了。

    好现在考虑加值。给((2,2),(3,3))的矩阵加上值。
    在差分数组里面就是这样的

    0 0 0 0 0 
    0 + 0 - 0
    0 0 0 0 0
    0 - 0 + 0
    

    就等于正常数组里面的

    0 0 0 0 0
    0 + + 0 0
    0 + + 0 0
    0 0 0 0 0
    

    即在给((x_1,y_1),(x_2,y_2))加值时。我们需要给((x_1,y_1),(x_2+1,y_2+1))加,((x_1,y_2+1),(x_2+1,y_1))减。
    因为统计数组时,点((i,j))的值为以((i,j))为右下角,((1,1))为左上角的差分矩阵的和。

    题解

    #include<cstdio>
    #include<cmath>
    #include<iostream>
    #include<algorithm>
    #include<cstring>
    using namespace std;
    int n,m;
    int read(){
        int x=0,w=1;char ch=getchar();
        while(ch>'9'||ch<'0'){if(ch=='-')w=-1;ch=getchar();}
        while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar();
        return x*w;
    }
    
    struct node{
        int t[2050][2050];
        void add(int x,int y,int v){
            for(int i=x;i<=n;i+=(i&(-i)))
                for(int j=y;j<=m;j+=(j&(-j)))
                t[i][j]+=v;
        }
        int query(int x,int y){
            int sum=0;
            for(int i=x;i;i-=(i&(-i)))
                for(int j=y;j;j-=(j&(-j)))
                sum+=t[i][j];
            return sum;
        }
    }Q,Qi,Qj,Qij;
    
    void add(int x,int y,int v){
        Q.add(x,y,v);Qi.add(x,y,v*x);
        Qj.add(x,y,v*y);Qij.add(x,y,v*x*y);
    }
    
    int query(int x,int y){
        return Q.query(x,y)*(x*y+x+y+1)-Qi.query(x,y)*(y+1)-Qj.query(x,y)*(x+1)+Qij.query(x,y);
    }
    
    int main(){
        n=read();m=read();
        char opt[10];
        while(scanf("%s",opt)==1){
            int xa=read(),ya=read(),xb=read(),yb=read();
            if(opt[0]=='L'){
                int v=read();
                add(xa,ya,v);add(xb+1,ya,-v);
                add(xb+1,yb+1,v);add(xa,yb+1,-v);
            }
            else {
                printf("%d
    ",query(xb,yb)-query(xb,ya-1)-query(xa-1,yb)+query(xa-1,ya-1));
            }
        }
        return 0;
    }
    
  • 相关阅读:
    crystal report 用存储过程的问题。
    新的开始—2014
    C#基础(二)——C#中的构造函数
    C#基础(一)——C#中反斜杠/n与/r的区别
    Html基础(一)
    yield关键字, default关键字, 别名关键字
    让 wpf tabcontrol 延缓初始化每个tab item content
    MVC,MVP,MVVM(补充)
    Focus scope in WPF
    Wpf ItemsControl 开启UI Virtualization 的条件
  • 原文地址:https://www.cnblogs.com/hhh1109/p/9737494.html
Copyright © 2020-2023  润新知