【bzoj 3132】上帝造題的七分鐘

傳送門

解題思路

二維樹狀數組。
對於修改操作單開一個矩陣,修改時利用差分思想,這樣每個點S[i][j] 的前綴和表示這個點修改了多少。
對於一個查詢(x,y) ,單獨考慮從(0,0)(x,y) 的每一個點,一個點(i,j) 會被算進從(i,j)(x,y) 所有點的前綴和裏,所以(i,j) 對本次查詢的貢獻爲S[i][j]×(xi+1)×(yj+1)
拆開變成:S[i][j]×(x+1)×(y+1)S[i][j]×j×(x+1)S[i][j]×i×(y+1)+S[i][j]×i×j ,然後分別維護四個樹狀數組,查詢時加到一起。
代碼:

#include<algorithm>
#include<cmath>
#include<iostream>
#include<cstring>
#include<string>
#include<cstdio>
#include<cstdlib>
using namespace std;
int n,m;
struct ldx{
    int a[2050][2050];
    void add(int x,int y,int num){
        for(int i=x;i<=n;i+=i&(-i))
        for(int j=y;j<=m;j+=j&(-j))
        a[i][j]+=num;
    }
    int ch(int x,int y){
        int sum=0;
        for(int i=x;i>0;i-=i&(-i))
        for(int j=y;j>0;j-=j&(-j))
        sum+=a[i][j];
        return sum;
    }
}T1,T2,T3,T4;
inline void tj(int x,int y,int num){
    T1.add(x,y,num);
    T2.add(x,y,num*x);
    T3.add(x,y,num*y);
    T4.add(x,y,num*x*y);
}
inline int solve(int x,int y){
    return (x+1)*(y+1)*T1.ch(x,y)-(y+1)*T2.ch(x,y)-(x+1)*T3.ch(x,y)+T4.ch(x,y);
}
int main(){
    int ai,bi,ci,di,ei;
    char opt[5];
    scanf("%s%d%d",opt,&n,&m);
    while(~scanf("%s",opt)){
        if(opt[0]=='L'){
            scanf("%d%d%d%d%d",&ai,&bi,&ci,&di,&ei);
            tj(ai,bi,ei);tj(ci+1,di+1,ei);
            tj(ci+1,bi,-ei);tj(ai,di+1,-ei);
        }
        else {
            scanf("%d%d%d%d",&ai,&bi,&ci,&di);
            int ans=solve(ci,di)+solve(ai-1,bi-1)-solve(ci,bi-1)-solve(ai-1,di);
            printf("%d",ans);
        }
    }
    return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章