二维树状数组
二维树状数组
模板
单点修改,子矩阵查询
暴力的把一维拓展到二维,直接然后按照一维的方法搞就OK,参考代码:
void insert(int x,int y,int z)
{
for(int i=x;i<=n;i+=lowbit(i)) for(int j=y;j<=m;j+=lowbit(j)) d[i][j]+=z;
}
int getsum(int x,int y)
{
int sum=0;
for(int i=x;i;i-=lowbit(i)) for(int j=y;j;j-=lowbit(j))
sum+=d[i][j];
return sum;
}
二维差分
类似于一维的差分,我们可以得出:
子矩阵加,求子矩阵和
修改操作可以类似的转化为差分数组的
区间查询需要稍微推一下式子:
这里考虑一下
显然有
然后,有:
所以分别维护
例题
P4514 上帝造题的七分钟
板子题。
#include<bits/stdc++.h>
using namespace std;
const int maxn=2050;
int n,m;
struct treearray
{
int d[maxn][maxn],di[maxn][maxn],dj[maxn][maxn],dij[maxn][maxn];
int lowbit(int x){return x&(-x);}
void insert(int x,int y,int z)
{
for(int i=x;i<=n;i+=lowbit(i)) for(int j=y;j<=m;j+=lowbit(j))
{
d[i][j]+=z;
di[i][j]+=z*x;
dj[i][j]+=z*y;
dij[i][j]+=z*x*y;
}
}
int getsum(int x,int y)
{
int sum=0;
for(int i=x;i;i-=lowbit(i)) for(int j=y;j;j-=lowbit(j))
sum+=d[i][j]*(x+1)*(y+1)-di[i][j]*(y+1)-dj[i][j]*(x+1)+dij[i][j];
return sum;
}
}T;
void add(int a,int b,int c,int d,int z)
{
T.insert(a,b,z);
T.insert(a,d+1,-z);
T.insert(c+1,b,-z);
T.insert(c+1,d+1,z);
}
int qry(int a,int b,int c,int d)
{
return T.getsum(c,d)-T.getsum(a-1,d)-T.getsum(c,b-1)+T.getsum(a-1,b-1);
}
int main()
{
char op[10];
cin>>op;
scanf("%d%d",&n,&m);
while(scanf("%s",op)!=EOF)
{
int a,b,c,d;
scanf("%d%d%d%d",&a,&b,&c,&d);
if(op[0]=='L')
{
int z;
scanf("%d",&z);
add(a,b,c,d,z);
}
else printf("%d\n",qry(a,b,c,d));
}
}
P4054 JSOI2009 计数问题
单点修改的板子题,可以有效区分区间修改的题目。
#include<bits/stdc++.h>
using namespace std;
const int maxn=303;
int n,m;
struct treearray
{
short d[maxn][maxn];
int lowbit(int x){return x&(-x);}
void insert(int x,int y,int z)
{
for(int i=x;i<=n;i+=lowbit(i)) for(int j=y;j<=m;j+=lowbit(j)) d[i][j]+=z;
}
int getsum(int x,int y)
{
int sum=0;
for(int i=x;i;i-=lowbit(i)) for(int j=y;j;j-=lowbit(j))
sum+=d[i][j];
return sum;
}
void add(int xa,int ya,int xb,int yb,int z){insert(xa,ya,z);}
int qry(int xa,int ya,int xb,int yb)
{
return getsum(xb,yb)-getsum(xa-1,yb)-getsum(xb,ya-1)+getsum(xa-1,ya-1);
}
}col[105];
int mp[maxn][maxn];
int main()
{
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++) for(int j=1;j<=m;j++)
{
int x;
scanf("%d",&x);
mp[i][j]=x;
col[x].add(i,j,i,j,1);
}
int q;
scanf("%d",&q);
while(q--)
{
int op,xa,ya,xb,yb,c;
scanf("%d",&op);
if(op==1)
{
scanf("%d%d%d",&xa,&ya,&c);
col[mp[xa][ya]].add(xa,ya,xa,ya,-1);
col[c].add(xa,ya,xa,ya,1);
mp[xa][ya]=c;
}
else
{
scanf("%d%d%d%d%d",&xa,&xb,&ya,&yb,&c);
printf("%d\n",col[c].qry(xa,ya,xb,yb));
}
}
}
先咕着,做了后面的题再更。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· DeepSeek 开源周回顾「GitHub 热点速览」
· 记一次.NET内存居高不下排查解决与启示
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· .NET10 - 预览版1新功能体验(一)