二维树状数组

二维树状数组

模板

单点修改,子矩阵查询

暴力的把一维拓展到二维,直接然后按照一维的方法搞就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;
}

二维差分

类似于一维的差分,我们可以得出:

d[i][j]=a[i][j]a[i1][j]a[i][j1]+a[i1][j1]

子矩阵加,求子矩阵和

修改操作可以类似的转化为差分数组的 4 个单点修改。

区间查询需要稍微推一下式子:

i=1xj=1yh=1ik=1jd[h][k]

这里考虑一下 d[h][k] 出现的次数。

显然有 d[h][k] 出现了 (xh+1)×(yk+1) 次。

然后,有:

i=1xj=1yh=1ik=1jd[h][k]=i=1xj=1yd[i][j]×(xi+1)×(yj+1)=i=1xj=1yd[i][j]×(xy+x+y+1)d[i][j]×i×(y+1)d[i][j]×j×(x+1)+d[i][j]×i×j

所以分别维护 d[i][j]d[i][j]×id[i][j]×jd[i][j]×i×j 的树状数组。

例题

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));
        }
    }
}

先咕着,做了后面的题再更。

posted @   彬彬冰激凌  阅读(9)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· DeepSeek 开源周回顾「GitHub 热点速览」
· 记一次.NET内存居高不下排查解决与启示
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· .NET10 - 预览版1新功能体验(一)
点击右上角即可分享
微信分享提示