洛谷4514 上帝造题的七分钟(二维树状数组)

好久没写博客了.....
这段时间狂补一下

题目大意:
给定一个(n*n)的全0矩阵,每次有两种操作:
(L a b c d delta) 表示将左上角((a,b)),右下角((c,d))的矩阵加(delta)
(k a b c d) 表示求左上角((a,b)),右下角((c,d))的矩阵的和并输出

其中操作数(le 10^5)(n le 2048)

(此题卡空间,所以不要开(long long))

qwq既然是套路题,就直接说了

这个题考察的主要是二维树状数组

首先,类比一维,二维的树状数组(c[i][j])表示,第(i)行 向上 (lowbit(i))行,第(j)列,向左(lowbit(j))列的和是多少。

那么修改也就显而易见了

struct BIT{
	int c[maxn][maxn];
	void modify(int x,int y,int p)
	{
		for (int i=x;i<=n;i+=lowbit(i))
		  for (int j=y;j<=m;j+=lowbit(j))
		  {
		  	 c[i][j]+=p;
		  }
	}
	int query(int x,int y)
	{
		int ans=0;
		for (int i=x;i;i-=lowbit(i))
		{
			for (int j=y;j;j-=lowbit(j))
			{
				ans=ans+c[i][j];
			}
		}
		return ans;
	}
};

然后,我们来考虑怎么实现区间加呢?
一维的时候,我们运用的是差分的思想
那么我们对于二维,不妨使用(d[i][j]=a[i][j]-a[i-1][j]-a[i][j-1]+a[i][j])

那么我们对于修改一个((x1,y1)->(x2,y2))的矩阵,我们只需要让(d[x1][y1]+=delta,d[x1][y2+1]-=delta,d[x2+1][y1]-=delta,d[x2+1][y2+1]+=delta)
就可以轻松完成了qwq

那....要是用差分数组,求和貌似就需要一点学问啊
对于求一个((1,1)->(x,y))的矩阵的和
就是

[ans = sum_{i=1}^{x} sum_{j=1}^{y}sum_{h=1}^{i} sum_{k=1}^{j} d[h][k] ]

我们可以通过计算每个d的出现次数

来化简这个式子

[ans = sum_{i=1}^{x} sum_{j=1}^{y} d[i][j]*(x-i+1)*(y-j+1) ]

然后最终的式子就是

[sum_{i=1}^{x} sum_{j=1}^{y} d[i][j]*(xy+x+y+1) - d[i][j]*i*(y+1)-d[i][j]*j*(x+1)+d[i][j]*i*j ]

那么我们只需要维护四个树状数组,就OK了

直接上代码

// luogu-judger-enable-o2
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>

using namespace std;

inline int read()
{
   int x=0,f=1;char ch=getchar();
   while (!isdigit(ch)){if (ch=='-') f=-1;ch=getchar();}
   while (isdigit(ch)){x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}
   return x*f;
}

const int maxn = 2051;

int lowbit(int x)
{
	return (x & (-x));
}

int n,m;

struct BIT{
	int c[maxn][maxn];
	void modify(int x,int y,int p)
	{
		for (int i=x;i<=n;i+=lowbit(i))
		  for (int j=y;j<=m;j+=lowbit(j))
		  {
		  	 c[i][j]+=p;
		  }
	}
	int query(int x,int y)
	{
		int ans=0;
		for (int i=x;i;i-=lowbit(i))
		{
			for (int j=y;j;j-=lowbit(j))
			{
				ans=ans+c[i][j];
			}
		}
		return ans;
	}
};

BIT ymh,ymhi,ymhj,ymhij;

char s[10];
int x1,x2,yy,y2;

void add(int x,int y,int p)
{
	ymh.modify(x,y,p);
	ymhi.modify(x,y,p*x);
	ymhj.modify(x,y,p*y);
	ymhij.modify(x,y,p*x*y);
}

int sum(int x,int y)
{
	return ymh.query(x,y)*(x*y+x+y+1)-ymhi.query(x,y)*(y+1)-ymhj.query(x,y)*(x+1)+ymhij.query(x,y);
}

signed main()
{
  scanf("%s",s+1);
  n=read(),m=read();
  while (scanf("%s",s+1)!=EOF)
  { 	 
     int p;
  	 if (s[1]=='L')
	   {
	   	  x1=read(),yy=read(),x2=read(),y2=read();
	   	  p=read();
	   	  add(x1,yy,p);
	   	  add(x1,y2+1,-p);
	   	  add(x2+1,yy,-p);
	   	  add(x2+1,y2+1,p);
	   }
	  else
	  {
	  	 x1=read(),yy=read(),x2=read(),y2=read();
	  	 printf("%d
",sum(x2,y2)-sum(x2,yy-1)-sum(x1-1,y2)+sum(x1-1,yy-1));
	  } 
  }
  return 0;
}

原文地址:https://www.cnblogs.com/yimmortal/p/10161389.html