3132: 上帝造题的七分钟 树状数组 二维区间加减+查询

题意很明确,似乎可以写二维线段树,然而我并不会QAQ。
本来只会一点一维的树状数组区间修改区间查询,今天又见识到了二维的,好神奇Orz。

转自Only the Strong Survive的题解:
对于矩阵A,A[i][j]表示[i,j]-[n,m]的增量。那么子矩阵[1,1]-[x,y]的总和为:

无限ym


#include<bits/stdc++.h>
#define N 2050
using namespace std;
int n,m;
char ch[5];
inline int read()
{
    int a=0,f=1; char c=getchar();
    while (c<'0'||c>'9') {if (c=='-') f=-1; c=getchar();}
    while (c>='0'&&c<='9') {a=a*10+c-'0'; c=getchar();}
    return a*f;
}

struct BIT
{
    int tree[N][N];

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

    inline void add(int x,int y,int val)
    {
        for (int i=x;i<=n;i+=lowbit(i))
            for (int j=y;j<=m;j+=lowbit(j))
                tree[i][j]+=val;
    }

    inline int query(int x,int y)
    {
        int tmp=0;
        for (int i=x;i;i-=lowbit(i))
            for (int j=y;j;j-=lowbit(j))
                 tmp+=tree[i][j];
        return tmp;
    }
} b1,b2,b3,b4;

inline void update(int x,int y,int val)
{
    b1.add(x,y,val); b2.add(x,y,y*val); b3.add(x,y,x*val); b4.add(x,y,x*y*val);
}

inline int query(int x,int y)
{
    return (x+1)*(y+1)*b1.query(x,y)-(x+1)*b2.query(x,y)-(y+1)*b3.query(x,y)+b4.query(x,y);
}

int main()
{
    scanf("%s",ch); 
    n=read(); m=read();
    int x1,x2,y1,y2,val;
    while (scanf("%s",ch)!=EOF)
    {
        x1=read(); y1=read(); x2=read(); y2=read();
        if (ch[0]=='L')
        {
            val=read();
            update(x2+1,y2+1,val); update(x1,y1,val);
            update(x2+1,y1,-val); update(x1,y2+1,-val);
        }
        else printf("%d\n",query(x2,y2)+query(x1-1,y1-1)-query(x1-1,y2)-query(x2,y1-1));
    }
    return 0;
}

你可能感兴趣的:(3132: 上帝造题的七分钟 树状数组 二维区间加减+查询)