1. 程式人生 > >[BZOJ3132]上帝造題的七分鐘

[BZOJ3132]上帝造題的七分鐘

inline get 復雜度 oid spa pla tchar sca ble

bzoj

descirption

反正就是要你支持二維樹狀數組矩形修改矩形查詢。

sol

類似於一維樹狀數組的區間修改區間查詢(可以去參考lcf學長的blog),我們稍稍推一下式子。
假設原二維數組是\(a_{i,j}\),我們設其差分數組為\(d_{i,j}=a_{i,j}-a_{i-1,j}-a_{i,j-1}+a_{i-1,j-1}\),那麽有:
\[a_{x,y}=\sum_{i=1}^x\sum_{j=1}^yd_{i,j}\\\sum_{i=1}^{x}\sum_{j=1}^ya_{i,j}=\sum_{i=1}^x\sum_{j=1}^y\sum_{k=1}^i\sum_{l=1}^jd_{k,l}\\=\sum_{i=1}^{x}\sum_{j=1}^yd_{i,j}\times(x-i+1)\times(y-j+1)\\=(xy+x+y+1)\sum_{i=1}^{x}\sum_{j=1}^yd_{i,j}-(y+1)\sum_{i=1}^{x}\sum_{j=1}^yi\times d_{i,j}-(x+1)\sum_{i=1}^{x}\sum_{j=1}^yj\times d_{i,j}+\sum_{i=1}^{x}\sum_{j=1}^yij\times d_{i,j}\]


所以使用四個二維樹狀數組維護一下就可以了。復雜度\(O(n\log^2n)\)

code

#include<cstdio>
#include<algorithm>
using namespace std;
int gi(){
    int x=0,w=1;char ch=getchar();
    while ((ch<'0'||ch>'9')&&ch!='-') ch=getchar();
    if (ch=='-') w=0,ch=getchar();
    while (ch>='0'&&ch<='9') x=(x<<3)+(x<<1)+ch-'0',ch=getchar();
    return w?x:-x;
}
#define ll long long
const int N = 2050;
int n,m;ll c[N][N],ci[N][N],cj[N][N],cij[N][N];
void modify(int x,int y,int v){
    for (int i=x;i<=n;i+=i&-i)
        for (int j=y;j<=m;j+=j&-j){
            c[i][j]+=v;
            ci[i][j]+=v*x;
            cj[i][j]+=v*y;
            cij[i][j]+=v*x*y;
        }
}
ll query(int x,int y){
    ll res=0;
    for (int i=x;i;i-=i&-i)
        for (int j=y;j;j-=j&-j){
            res+=(x*y+x+y+1)*c[i][j];
            res-=(y+1)*ci[i][j];
            res-=(x+1)*cj[i][j];
            res+=cij[i][j];
        }
    return res;
}
int main(){
    n=gi();m=gi();char op;
    while (scanf(" %c",&op)!=EOF)
        if (op=='L'){
            int a=gi(),b=gi(),c=gi(),d=gi(),v=gi();
            modify(a,b,v);modify(a,d+1,-v);
            modify(c+1,b,-v);modify(c+1,d+1,v);
        }else{
            int a=gi(),b=gi(),c=gi(),d=gi();
            printf("%lld\n",query(c,d)-query(a-1,d)-query(c,b-1)+query(a-1,b-1));
        }
    return 0;
}

[BZOJ3132]上帝造題的七分鐘