#树状数组#洛谷 4514 上帝造题的七分钟

本文介绍了一种使用树状数组实现二维差分的方法,用于高效处理二维数组的区间加和区间查询操作。通过数学推导,展示了如何将复杂的二维前缀和转化为树状数组可以维护的形式,包括直接值、x方向累加、y方向累加以及xy方向的乘积累加。

题目

一开始初始为0的二维数组,需要维护区间加和区间查询


分析

首先要思考如何表示二维前缀和以差分实现
s[x][y]=∑i=1n∑j=1n∑p=1i∑q=1ja[p][q]s[x][y]=\sum_{i=1}^n\sum_{j=1}^n\sum_{p=1}^i\sum_{q=1}^ja[p][q]s[x][y]=i=1nj=1np=1iq=1ja[p][q]
s[x][y]=∑i=1n∑j=1na[i][j]∗(x−i+1)∗(y−j+1)s[x][y]=\sum_{i=1}^n\sum_{j=1}^na[i][j]*(x-i+1)*(y-j+1)s[x][y]=i=1nj=1na[i][j](xi+1)(yj+1)
s[x][y]=∑i=1n∑j=1na[i][j]∗(xy+x+y+1)+a[i][j]∗i(y+1)+a[i][j]∗(x+1)j+a[i][j]ijs[x][y]=\sum_{i=1}^n\sum_{j=1}^na[i][j]*(xy+x+y+1)+a[i][j]*i(y+1)+a[i][j]*(x+1)j+a[i][j]ijs[x][y]=i=1nj=1na[i][j](xy+x+y+1)+a[i][j]i(y+1)+a[i][j](x+1)j+a[i][j]ij
所以这四个东西用树状数组维护


代码

#include <cstdio>
#include <cctype>
#define rr register
#define getchar() (p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<13,stdin)),p1==p2?EOF:*p1++)
using namespace std;
int n,m; char buf[1<<13],*p1,*p2;
inline signed iut(){
	rr int ans=0,f=1; rr char c=getchar();
	while (!isdigit(c)) f=(c=='-')?-f:f,c=getchar();
	while (isdigit(c)) ans=(ans<<3)+(ans<<1)+(c^48),c=getchar();
	return ans*f;
}
inline void print(int ans){
	if (ans<0) putchar('-'),ans=-ans;
	if (ans>9) print(ans/10);
	putchar(ans%10+48);
}
struct lowbit{
	int c[2051][2051];
	inline void add(int x,int y,int z){
		rr int y1=y;
		for (;x<=n;x+=-x&x)
		for (y=y1;y<=m;y+=-y&y) c[x][y]+=z;
	}
	inline signed query(int x,int y){
		rr int ans=0,y1=y;
		for (;x;x-=-x&x)
		for (y=y1;y;y-=-y&y) ans+=c[x][y];
		return ans;
	}
}a,a_x,a_y,a_xy;
inline void Add(int x,int y,int z){a.add(x,y,z),a_x.add(x,y,z*x),a_y.add(x,y,z*y),a_xy.add(x,y,z*x*y);}
inline signed Query(int x,int y){return a.query(x,y)*(x*y+x+y+1)-a_x.query(x,y)*(y+1)-a_y.query(x,y)*(x+1)+a_xy.query(x,y);}
signed main(){
	n=iut(),m=iut(),getchar();
	for (rr char c=getchar();c=='k'||c=='L';getchar(),c=getchar()){
		rr int x1=iut(),y1=iut(),x2=iut(),y2=iut(),z;
		if (c=='L') z=iut();
		if (c=='L') Add(x1,y1,z),Add(x2+1,y1,-z),Add(x1,y2+1,-z),Add(x2+1,y2+1,z);
		    else print(Query(x2,y2)-Query(x1-1,y2)-Query(x2,y1-1)+Query(x1-1,y1-1)),putchar(10);
	}
	return 0;
}
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值