【bzoj 3132】上帝造题的七分钟

传送门

解题思路

二维树状数组。
对于修改操作单开一个矩阵,修改时利用差分思想,这样每个点 S[i][j] S [ i ] [ j ] 的前缀和表示这个点修改了多少。
对于一个查询 (x,y) ( x , y ) ,单独考虑从 (0,0) ( 0 , 0 ) (x,y) ( x , y ) 的每一个点,一个点 (i,j) ( i , j ) 会被算进从 (i,j) ( i , j ) (x,y) ( x , y ) 所有点的前缀和里,所以 (i,j) ( i , j ) 对本次查询的贡献为 S[i][j]×(xi+1)×(yj+1) S [ i ] [ j ] × ( x − i + 1 ) × ( y − j + 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 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;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值