学习笔记——二维树状数组

不知道为什么,就是想把这个坑给填了。。。

二维树状数组,本质上还是树状数组,只是在一维的基础上变成了二维。。。

单点修改  1到i,j查询和一维基本一样,直接上代码

#include<iostream>
#include<cstdlib>
#include<cstdio>
#include<algorithm>
#define N 3010
using namespace std;
int a[N][N],n;
inline int lowbit(int x){
    return x&-x;
}
inline add(int x,int y,int del){
    for(int i=x;i<=n;i+=lowbit(i))
        for(int j=y;j<=n;j+=lowbit(j))
            a[i][j]+=del;
}
inline sum(int x,int y){
    int num=0;
    for(int i=x;i;i-=lowbit(i))
        for(int j=y;j;j-=lowbit(j))
            num+=a[i][j];
    return num;
}
inline void Jimmy(){
}
int main(){
    Jimmy();
    return 0;
} 

二维树状数组 单点修改 1到i,j查询

下面介绍一下区间修改和区间查询

定义bi,j表示i,j到n,n的修改量,实质是一个标记,在计算sigma时我们通过统计区间内标记个数得出区间修改量之和

我们设面积前缀和S

那么S(x,y)=sigma(i<=x and j<=y) ai,j +sigma(i<=x and j<=y) bi,j*(x-i+1)*(y-j+1)

     =sigma(i<=x and j<=y) ai,j +sigma(i<=x and j<=y) bi,j*(x+1)*(y+1)-sigma(i<=x and j<=y) bi,j*i*(y+1)-sigma(i<=x and j<=y) bi,j*j*(x+1)+sigma(i<=x and j<=y) bi,j*i*j

所以我们维护四个数组 bi,j  bi,j*i  bi,j*j  bi,j*i*j  就可以在logn时间内来完成查询了

区间修改呢,就是在矩形的四个角分别打上标记

x1,y1 +del
x2+1,y1 -del
x1,y2+1 -del
x2+1,y2+1 +del

每个标记修改4个数组,一共16次

然后就ok啦

#include<iostream>
#include<cstdlib>
#include<cstdio>
#include<algorithm>
#define N 3010
using namespace std;
int c1[N][N],c2[N][N],c3[N][N],c4[N][N],a[N][N],n,a[N][N],sum_[N][N];
inline int S(int x,int y){
    int num=sum_[x][y];
    for(int i=x;i;i-=lowbit(i))
        for(int j=y;j;j-=lowbit(j))
            num=num+c1[i][j]*(x+1)*(y+1)-c2[i][j]*(y+1)-c3[i][j]*(x+1)+c4[i][j];
    return num;
}
inline void change(int x,int y,int del){
    for(int i=x;i<=n;i+=lowbit(i))
        for(int j=y;j<=n;j+=lowbit(j)){
            c1[i][j]=c1[i][j]+del;
            c2[i][j]=c2[i][j]+del*i;
            c3[i][j]=c3[i][j]+del*j;
            c4[i][j]=c4[i][j]+del*i*j;
        }
}
inline int sum(int x1,int y1,int x2,int y2){
    return S(x2,y2)-S(x2,y1-1)-S(x1-1,y2)+S(x1-1,y1-1);
}
inline void add(int x1,int y1,int x2,int y2,int del){
    change(x1,y1,del);
    change(x1,y2+1,-del);
    change(x2+1,y1,-del);
    change(x2+1,y2+1,del);
}
inline void Jimmy(){
    scanf("%d",&n);
    for(int i=1;i<=n;i++)
        for(int j=1;j<=n;j++)
            scanf("%d%d",&a[i][j]);
    for(int i=1;i<=n;i++)
        for(int j=1;j<=n;j++)
            sum_[i][j]=sum_[i-1][j]+sum_[i][j-1]+a[i][j]-sum_[i][j];
}
int main(){
    Jimmy();
    return 0;
}

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

学习来源:http://tonyfang.is-programmer.com/posts/206991.html

orzTonyFang

但是方老师原来的公式写错了,公式看这篇,代码正确性不是很保证,欢迎指出BUG

时间: 2024-11-04 19:00:35

学习笔记——二维树状数组的相关文章

USACO5.3 IDDFS_强连通_二维树状数组_斐蜀定理_矩形切割

启发式搜索 启发式搜索的主要思想是通过评价一个状态有"多好"来改进对于解的搜索. 方法#1:启发式剪枝 估价函数最简单最普通的用法是进行剪枝.假设有一个求最小代价的一个搜索,使用一个可行的估价函数.如果搜到当前状态时代价为A,这个状态的估价函数是B,那么从这个状态开始搜所能得到的最小代价是A+B.如果当前最优解是C满足C 方法#2:最佳优先搜索 最佳搜索可以看成贪心的深度优先搜索. 与一般搜索随意扩展后继节点不同,最优优先搜索按照估价函数所给的他们的"好坏"的顺序扩

(二维树状数组)E - Stars

E - Stars 题意:B表示点亮改点,D表示熄灭,Q查询区间内亮的个数 Sample Input 5 B 581 145 B 581 145 Q 0 600 0 200 D 581 145 Q 0 600 0 200 AC代码: 1 #include <bits/stdc++.h> 2 3 using namespace std; 4 #define c_1(a) scanf("%d",&a) 5 #define c_2(a,b) scanf("%d%

【二维树状数组】See you~

https://www.bnuoj.com/v3/contest_show.php?cid=9148#problem/F [题意] 给定一个矩阵,每个格子的初始值为1.现在可以对矩阵有四种操作: A x y n1 :给格点(x,y)的值加n1 D x y n1: 给格点(x,y)的值减n1,如果现在格点的值不够n1,把格点置0 M x1 y1 x2 y2:(x1,y1)移动给(x2,y2)n1个 S x1 y1 x2 y2 查询子矩阵的和 [思路] 当然是二维树状数组 但是一定要注意:lowbi

POJ 1195 Mobile phones(二维树状数组)

题目链接:POJ 1195 题意: 给出一个S*S的矩阵(行.列号从1开始),每个元素初始值为0,有两种操作:一种是第X行第Y列元素值加A:另一种是查询给定范围矩阵的所有元素之和(L<=X<=R,B<=Y<=T). 分析: 查询给定范围矩阵的所有元素之和是二维区间和,可以转换为二维前缀和求值.类比一维前缀和求法,二维区间和S(L, B, R, T) = S(1, 1, R, T) - S(1 ,1, L-1, T) - S(1, 1, R, B-1) + S(1, 1, L-1,

POJ 2155 Matrix(二维树状数组,绝对具体)

Matrix Time Limit: 3000MS   Memory Limit: 65536K Total Submissions: 20599   Accepted: 7673 Description Given an N*N matrix A, whose elements are either 0 or 1. A[i, j] means the number in the i-th row and j-th column. Initially we have A[i, j] = 0 (1

HDU 5465 Clarke and puzzle Nim游戏+二维树状数组

题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=5465 Clarke and puzzle Accepts: 42 Submissions: 269 Time Limit: 4000/2000 MS (Java/Others) Memory Limit: 65536/65536 K (Java/Others) 问题描述 克拉克是一名人格分裂患者.某一天,有两个克拉克(aa和bb)在玩一个方格游戏. 这个方格是一个n*mn∗m的矩阵,每个格子里有一

HDOJ 4456 Crowd 离散化+二维树状数组

将坐标旋转45度就可以得到正方形,可以用二维树状数组求解... 为了节省内存,提前将树状数组中会被更新的点全都存下来,并离散化 Crowd Time Limit: 5000/2000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 1199    Accepted Submission(s): 282 Problem Description City F in the south

POJ2029:Get Many Persimmon Trees(二维树状数组)

Description Seiji Hayashi had been a professor of the Nisshinkan Samurai School in the domain of Aizu for a long time in the 18th century. In order to reward him for his meritorious career in education, Katanobu Matsudaira, the lord of the domain of

POJ1195 Mobile phones 【二维树状数组】

Mobile phones Time Limit: 5000MS   Memory Limit: 65536K Total Submissions: 14288   Accepted: 6642 Description Suppose that the fourth generation mobile phone base stations in the Tampere area operate as follows. The area is divided into squares. The