Luogu 4514 上帝造题的七分钟

二维差分+树状数组。

定义差分数组$d_{i, j} = a_{i, j} + a_{i - 1, j - 1} - a_{i, j - 1} - a_{i - 1, j}$,有$a_{i, j} = \sum_{x = 1}^{i}\sum_{y = 1}^{j}d_{i, j}$。

我们要求$sum(n, m) = \sum_{i = 1}^{n}\sum_{j = 1}^{m}a_{i, j} $,

代入$a_{i, j}$,得$sum(n, m) = \sum_{i = 1}^{n}\sum_{j = 1}^{m}\sum_{x = 1}^{i}\sum_{y = 1}^{j}d_{x, y}$。

列一下发现$d_{x, y}$出现了$(n - x + 1) * (m - y + 1)$次。

那么$sum(n, m) = \sum_{i = 1}^{n}\sum_{j = 1}^{m}d_{i, j} * (n - i + 1) * (m - j + 1)$。

把$(n + 1),(m + 1),i, j$看作四项展开,得到$(n + 1) * (m + 1)\sum_{i = 1}^{n}\sum_{j = 1}^{m}d_{i, j} + \sum_{i = 1}^{n}\sum_{j = 1}^{m}d_{i, j} * i * j - (m + 1)  \sum_{i = 1}^{n}\sum_{j = 1}^{m}d_{i, j} * i - (n + 1)\sum_{i = 1}^{n}\sum_{j = 1}^{m}d_{i, j} * j$。

两个$\sum$可以用一个二维树状数组维护,这样子维护四个树状数组即可(修改好长)

时间复杂度$O(qlognlogm)$。

另外,longlong在Luogu上会MLE最后两个点,要用int

Code:

#include <cstdio>
#include <cstring>
using namespace std;
typedef int ll;

const int N = 2050;

int n, m;

template <typename T>
inline void read(T &X) {
    X = 0; char ch = 0; T op = 1;
    for(; ch > '9'|| ch < '0'; ch = getchar())
        if(ch == '-') op = -1;
    for(; ch >= '0' && ch <= '9'; ch = getchar())
        X = (X << 3) + (X << 1) + ch - 48;
    X *= op;
}

struct BinaryIndexTree {
    ll arr[N][N];
    
    #define lowbit(p) (p & (-p))
    
    inline void modify(int x, int y, ll v) {
        for(int i = x; i <= n; i += lowbit(i))
            for(int j = y; j <= m; j += lowbit(j))
                arr[i][j] += v;
    }
    
    inline ll query(int x, int y) {
        ll res = 0LL;
        for(int i = x; i > 0; i -= lowbit(i))
            for(int j = y; j > 0; j -= lowbit(j))
                res += arr[i][j];
        return res;
    }
    
} sum, mulij, muli, mulj;

inline int min(int x, int y) {
    return x > y ? y : x;
}

inline int max(int x, int y) {
    return x > y ? x : y;
}

inline ll qSum(int x, int y) {
    return 1LL * (x + 1) * (y + 1) * sum.query(x, y) + 1LL * mulij.query(x, y) 
        - 1LL * (y + 1) * muli.query(x, y) - 1LL * (x + 1) * mulj.query(x, y);
}

int main() {
//    freopen("Sample.txt", "r", stdin);
    
    char op = getchar();
    read(n), read(m);
    for(; ; ) {
        for(op = getchar(); op != 'L' && op != 'k' && op >= 0; op = getchar());
        if(op < 0) break;
        
        if(op == 'L') {
            int a, b, c, d; ll v;
            read(a), read(b), read(c), read(d), read(v);
            int lx = min(a, c), ly = min(b, d), rx = max(a, c), ry = max(b, d);
            sum.modify(lx, ly, v);
            sum.modify(rx + 1, ry + 1, v);
            sum.modify(lx, ry + 1, -v);
            sum.modify(rx + 1, ly, -v);
            
            muli.modify(lx, ly, v * lx);
            muli.modify(rx + 1, ry + 1, v * (rx + 1));
            muli.modify(lx, ry + 1, -v * lx);
            muli.modify(rx + 1, ly, -v * (rx + 1));

            mulj.modify(lx, ly, v * ly);
            mulj.modify(rx + 1, ry + 1, v * (ry + 1));
            mulj.modify(lx, ry + 1, -v * (ry + 1));
            mulj.modify(rx + 1, ly, -v * ly);
            
            mulij.modify(lx, ly, v * lx * ly);
            mulij.modify(rx + 1, ry + 1, v * (rx + 1) * (ry + 1));
            mulij.modify(lx, ry + 1, -v * (ry + 1) * lx);
            mulij.modify(rx + 1, ly, -v * (rx + 1) * ly);
        } else {
            int a, b, c, d;
            read(a), read(b), read(c), read(d);
            int lx = min(a, c), ly = min(b, d), rx = max(a, c), ry = max(b, d);
            printf("%d\n", qSum(rx, ry) + qSum(lx - 1, ly - 1) - qSum(rx, ly - 1) - qSum(lx - 1, ry));
        }
    }
    return 0;
}
View Code

 

posted @ 2018-09-10 12:58  CzxingcHen  阅读(127)  评论(0编辑  收藏  举报