[Template] Tree Array (6)

Last time we talked about the single-point plus interval search of the two-dimensional tree array.
Then it is not difficult for us to add a single point to the interval.
We let the tree array maintain the difference array, but it becomes a two-dimensional difference, It's almost the same.
We can rewrite it like this in one dimension

int c[N][N],n,m;
void add(int x,int y,int s){
    for(int i=x;i<=n;i+=i&-i)
        for(int j=y;j<=m;j+=j&-j)
            c[i][j]+=s;
}
int query(int x,int y,int s=0){
    for(int i=x;i;i-=i&-i)
        for(int j=y;j;j-=i&-j)
            s+=c[i][j];
}
void Add(int x1,int y1,int x2,int y2,int s){
    add(x1,y1,s); add(x1,y2+1,-s); add(x2+1,y1,-s); add(x2+1,y2+1,s);
}

In fact, the two-dimensional tree array can also be added to the interval, and the interval can be checked.
And it is said that the line segment tree cannot be maintained by the line segment tree....
Let's take a lookBookBoard Questions: Seven Minutes When God Made Questions

So how do we do it? We still follow the one-dimensional push persimmon.
But today, I didn’t feel good to push persimmon according to the previous method, so I got a new push method.
Because the prefix sum of the difference array we maintain is the The value of a single point, that is to say, when we calculate \(a_i\) , each value of \(c_1\sim c_i\) will be calculated once. In
this way, we calculate \(\sum_{i=1}^na_i\ ) When, \(c_1\) should appear \(n\) times, \(c_2\) should appear \(n-1\) times, ... , \(c_k\) will appear \(n-k +1\) times, ... , \(c_n\) will appear once. So
\[ ans=\sum_{i=1}^na_i=\sum_{i=1}^n\sum_{j=1} ^ic_j=\sum_{i=1}^nc_i*(n-i+1)=\sum_{i=1}^nc_i*(n+1)-\sum_{i=1}^nc_i*i \]
In this way, we can use two tree-like arrays to maintain the sum of \(c_i\) and the sum of \(c_i*i\) respectively.
And the conclusion we drew before is not wrong, if we split it like this
\[ ans=\sum_{i=1}^nc_i*(n-i+1)=\sum_{i=1}^nc_i*n+\sum_{i=1}^nc_i*(i-1) \]
It becomes maintenance \(c_I\) and \(c_i*(i-1)\) , the final result should be the same, which one to use depends on personal preference... (It seems that the previous one is more comfortable to use ..)


The situation is extended to two-dimensional, except that the two-dimensional difference is complicated by one (hen) (duo), the principle is the same.
We still use \(c_{i,j}\) to maintain the difference array, so obviously \(\ sum_{i=1}^n\sum_{j=1}^mc_{i,j}=a_{n,m}\)
and then follow the one-dimensional, split a query into four, for each query,
\[ ans=\sum_{i=1}^n\sum_{j=1}^m\sum_{x=1}^i\sum_{y=1}^jc_{ij} \]
It is obvious that every The number of times \(c_i,j\) is used is equal to the area of ​​the rectangle with \((i,j)\) as the upper left corner and \((n,m)\) as the lower right corner (you can draw a picture if you don’t believe me) try), which is \((n-i+1)*(m-j+1)\) , so
\[ ans=\sum_{i=1}^n\sum_{j=1}^m\sum_ {x=1}^i\sum_{y=1}^jc_{ij}=\sum_{i=1}^n\sum_{j=1}^mc_{ij}*(n-i+1)* (m-j+1) \\ =\sum_{i=1}^n\sum_{j=1}^mc_{i,j}*(n+1)*(m+1)-\sum_{i =1}^n\sum_{j=1}^mc_{i,j}*i*(m+1)-\sum_{i=1}^n\sum_{j=1}^mc_{i,j }*j*(n+1)+\sum_{i=1}^n\sum_{j=1}^mc_{i,j}*i*j \]
So according to the routine, we only need to open four tree arrays to maintain \(c_{i,j},c_{i,j}*i,c_{i,j}*j,c_{i,j}*i* j\) will do..

Whether it is interval addition or interval checking, it is very cumbersome qwq...
The code is given below;

#include <cstdio>
inline int gn(int a=0,char c=0,int f=1){
    for(;(c<'0'||c>'9')&&c!='-';c=getchar());
    if(c=='-') c=getchar(),f=-1;
    for(;c>47&&c<58;c=getchar()) a=a*10+c-48;
return a*f;}
struct BIT{
    int c[2050][2050],n,m;
    
    void add(int x,int y,int s){
        for(int i=x;i<=n;i+=i&-i)
            for(int j=y;j<=m;j+=j&-j)
                c[i][j]+=s;
    }
    
    int query(int x,int y,int s=0){
        for(int i=x;i;i-=i&-i)
            for(int j=y;j;j-=j&-j)
                s+=c[i][j];
        return s;
    }
    
}a,b,c,d;

void Add(int x,int y,int s){
    a.add(x,y,s); b.add(x,y,s*x); c.add(x,y,s*y); d.add(x,y,s*x*y);
}
int Query(int x,int y){
    return a.query(x,y)*(x+1)*(y+1)-b.query(x,y)*(y+1)-c.query(x,y)*(x+1)+d.query(x,y); 
}

int main(){
    int n=gn(),m=gn(); char opt[4];
    a.n=b.n=c.n=d.n=n; a.m=b.m=c.m=d.m=m;
    while(~scanf("%s",opt)){
        if(opt[0]=='L'){
            int x1=gn(),y1=gn(),x2=gn(),y2=gn(),s=gn();
            Add(x1,y1,s); Add(x1,y2+1,-s); Add(x2+1,y1,-s); Add(x2+1,y2+1,s); 
        }
        else{
            int x1=gn(),y1=gn(),x2=gn(),y2=gn();
            printf("%d\n",Query(x2,y2)-Query(x1-1,y2)-Query(x2,y1-1)+Query(x1-1,y1-1));
        }
    }
} 

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=325078002&siteId=291194637