# BZOJ3132 上帝造题的七分钟 【二维树状数组】

## 题目

“第一分钟，X说，要有矩阵，于是便有了一个里面写满了0的n×m矩阵。

   ——《上帝造裸题的七分钟》


## 输入格式

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

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

X 4 4

L 1 1 3 3 2

L 2 2 4 4 1

k 2 2 3 3

12

## 二维树状数组

struct BIT{
int A[maxn][maxn];
for (int i = x; i <= n; i += lbt(i))
for (int j = y; j <= m; j += lbt(j))
A[i][j] += v;
}
int sum(int x,int y){
int ans = 0;
for (int i = x; i > 0; i -= lbt(i))
for (int j = y; j > 0; j -= lbt(j))
ans += A[i][j];
return ans;
}
};

## 区间修改的树状数组

sum(i,j)=D[1i]+D[1i+1]+D[1i+2]+...+D[1j]
=(ji+1)ik=1D[k]+(ji)D[i+1]+(ji1)D[i+2]+....+D[j]
=(j+1)jk=iD[k](jD[j]+(j1)D[j1]+(j2)D[j2]+...+iD[i])
=(j+1)SUM(D[x],i,j)SUM(D[x]x,i,j)

## 二维树状数组

#include<cstdio>
#define lbt(u) (u & -u)
const int maxn = 2050,maxm = 100005,INF = 1000000000;
inline int RD(){
int out = 0,flag = 1; char c = getchar();
while (c < 48 || c > 57) {if (c == '-') flag = -1; c = getchar();}
while (c >= 48 && c <= 57) {out = (out << 1) + (out << 3) + c - '0'; c = getchar();}
return out * flag;
}
int n,m;
struct BIT{
int A[maxn][maxn];
for (int i = x; i <= n; i += lbt(i))
for (int j = y; j <= m; j += lbt(j))
A[i][j] += v;
}
int sum(int x,int y){
int ans = 0;
for (int i = x; i > 0; i -= lbt(i))
for (int j = y; j > 0; j -= lbt(j))
ans += A[i][j];
return ans;
}
}A,B,C,D;
}
void update(int x1,int y1,int x2,int y2,int v){
}
int Sum(int x,int y){
return (x + 1) * (y + 1) * A.sum(x,y) - (x + 1) * B.sum(x,y) - (y + 1) * C.sum(x,y) + D.sum(x,y);
}
int Query(int x1,int y1,int x2,int y2){
return Sum(x2,y2) - Sum(x1 - 1,y2) - Sum(x2,y1 - 1) + Sum(x1 - 1,y1 - 1);
}
int main(){
n = RD(); m = RD(); int x1,y1,x2,y2,d;
while (true){
char c = getchar();
while (c != EOF && c != 'L' && c != 'k') c = getchar();
if (c == EOF) break;
else if (c == 'L'){
x1 = RD(); y1 = RD(); x2 = RD(); y2 = RD(); d = RD();
update(x1,y1,x2,y2,d);
}else {
x1 = RD(); y1 = RD(); x2 = RD(); y2 = RD();
printf("%d\n",Query(x1,y1,x2,y2));
}
}
return 0;
}

posted @ 2017-12-24 09:32  Mychael  阅读(145)  评论(0编辑  收藏  举报