[BZOJ3132]上帝造题的七分钟

bzoj

descirption

反正就是要你支持二维树状数组矩形修改矩形查询。

sol

类似于一维树状数组的区间修改区间查询(可以去参考lcf学长的blog),我们稍稍推一下式子。
假设原二维数组是\(a_{i,j}\),我们设其差分数组为\(d_{i,j}=a_{i,j}-a_{i-1,j}-a_{i,j-1}+a_{i-1,j-1}\),那么有:

\[a_{x,y}=\sum_{i=1}^x\sum_{j=1}^yd_{i,j}\\\sum_{i=1}^{x}\sum_{j=1}^ya_{i,j}=\sum_{i=1}^x\sum_{j=1}^y\sum_{k=1}^i\sum_{l=1}^jd_{k,l}\\=\sum_{i=1}^{x}\sum_{j=1}^yd_{i,j}\times(x-i+1)\times(y-j+1)\\=(xy+x+y+1)\sum_{i=1}^{x}\sum_{j=1}^yd_{i,j}-(y+1)\sum_{i=1}^{x}\sum_{j=1}^yi\times d_{i,j}-(x+1)\sum_{i=1}^{x}\sum_{j=1}^yj\times d_{i,j}+\sum_{i=1}^{x}\sum_{j=1}^yij\times d_{i,j} \]

所以使用四个二维树状数组维护一下就可以了。复杂度\(O(n\log^2n)\)

code

#include<cstdio>
#include<algorithm>
using namespace std;
int gi(){
	int x=0,w=1;char ch=getchar();
	while ((ch<'0'||ch>'9')&&ch!='-') ch=getchar();
	if (ch=='-') w=0,ch=getchar();
	while (ch>='0'&&ch<='9') x=(x<<3)+(x<<1)+ch-'0',ch=getchar();
	return w?x:-x;
}
#define ll long long
const int N = 2050;
int n,m;ll c[N][N],ci[N][N],cj[N][N],cij[N][N];
void modify(int x,int y,int v){
	for (int i=x;i<=n;i+=i&-i)
		for (int j=y;j<=m;j+=j&-j){
			c[i][j]+=v;
			ci[i][j]+=v*x;
			cj[i][j]+=v*y;
			cij[i][j]+=v*x*y;
		}
}
ll query(int x,int y){
	ll res=0;
	for (int i=x;i;i-=i&-i)
		for (int j=y;j;j-=j&-j){
			res+=(x*y+x+y+1)*c[i][j];
			res-=(y+1)*ci[i][j];
			res-=(x+1)*cj[i][j];
			res+=cij[i][j];
		}
	return res;
}
int main(){
	n=gi();m=gi();char op;
	while (scanf(" %c",&op)!=EOF)
		if (op=='L'){
			int a=gi(),b=gi(),c=gi(),d=gi(),v=gi();
			modify(a,b,v);modify(a,d+1,-v);
			modify(c+1,b,-v);modify(c+1,d+1,v);
		}else{
			int a=gi(),b=gi(),c=gi(),d=gi();
			printf("%lld\n",query(c,d)-query(a-1,d)-query(c,b-1)+query(a-1,b-1));
		}
	return 0;
}
posted @ 2018-07-03 12:18  租酥雨  阅读(185)  评论(0编辑  收藏  举报