文章出处
题意:
给定n×m的矩阵,k个操作,每个操作给定矩阵左上角和右下角顶点,有两种操作,一是将该矩阵全部元素加上xx,二是询问该矩阵全部元素的和。
数据范围:0≤n,m≤2048,k≤200000,0≤x≤500 0 ≤n,m≤2048,k≤200000,0≤x≤500,保证计算过程中所有数不超过带符号整型。
分析:
区间求和问题我们可以转化为前缀和问题,即对于[a,b]和[c,d][a,b]和[c,d]之间的矩阵答案为sum(c,d)−sum(c,b−1)−sum(a−1,d)+sum(a,b)sum(c,d)−sum(c,b−1)−sum(a−1,d)+sum(a,b),这样就可以变为单点查询。
对于区间修改问题,我们利用差分的思想,将区间修改转化为单点修改。
令每个位置的元素为newai,j=ai,j−ai−1,j−ai,j−1+ai−1,j−1newai,j=ai,j−ai−1,j−ai,j−1+ai−1,j−1,那么ax,y=∑xi=1∑yj=1newai,jax,y=∑i=1x∑j=1ynewai,j
sum(a,b)=∑ax=1∑by=1ax,y=∑ax=1∑by=1∑xi=1∑yj=1newai,jsum(a,b)=∑x=1a∑y=1bax,y=∑x=1a∑y=1b∑i=1x∑j=1ynewai,j
考虑[1,1][1,1]内每个元素对于sum(a,b)sum(a,b)的贡献,
sum(a,b)=∑ai=1∑bj=1(a+1−i)×(b+1−j)×newax,ysum(a,b)=∑i=1a∑j=1b(a+1−i)×(b+1−j)×newax,y
=(a+1)×(b+1)∑ai=1∑bj=1newai,j−(a+1)∑ai=1∑bj=1newai,j×j−(b+1)∑ai=1∑bj=1newai,j×i=(a+1)×(b+1)∑i=1a∑j=1bnewai,j−(a+1)∑i=1a∑j=1bnewai,j×j−(b+1)∑i=1a∑j=1bnewai,j×i
+∑ai=1∑bj=1i×j×newai,j+∑i=1a∑j=1bi×j×newai,j
这样对于每个点分别记录这四个值,单点更新单点查询套个二维树状数组即可。
代码
#include<iostream>
#include<cstdio>
#include<cstring>
#include<queue>
#include<vector>
#include<set>
#include<map>
#include<algorithm>
using namespace std;
const int maxn = 2500 + 5;
int bit[maxn][maxn][5];
void add(int x, int y, int val, int id)
{
for (int i = x; i < maxn; i += i & (-i)) {
for (int j = y; j < maxn; j += j & (-j)){
bit[i][j][id] += val;
}
}
}
int sum(int x, int y, int id)
{
int res = 0;
for(int i = x; i; i -= i & (-i)){
for(int j = y; j; j -= j & (-j)){
res += bit[i][j][id];
}
}
return res;
}
void Add(int a, int b, int dt)
{
add(a, b, dt, 1); add(a, b, dt * b, 2); add(a, b, dt * a, 3); add(a, b, dt * a * b, 4);
}
int Query(int c, int d)
{
int ans = (c + 1) * (d + 1) * sum(c, d, 1) - (d + 1) * sum(c, d, 3) - (c + 1) * sum(c, d, 2) + sum(c, d, 4);
return ans;
}
char s[10];
int main (void)
{
int n, m;scanf("%s%d%d", s, &n, &m);
int a, b, c, d, dt;
memset(bit, 0 ,sizeof(bit));
while(~scanf("%s", s)){
if(s[0] == 'L'){
scanf("%d%d%d%d%d", &a, &b, &c, &d, &dt);
Add(a, b, dt);
Add(a, d + 1, -dt);
Add(c + 1, b, -dt);
Add(c + 1, d + 1, dt);
}else{
scanf("%d%d%d%d", &a, &b, &c, &d);
if(a > c || b > d) swap(a, b), swap(c, d);
printf("%d\n", Query(c, d) - Query(a - 1, d) - Query(c, b - 1) + Query(a - 1, b - 1));
}
}
return 0;
}
2796

被折叠的 条评论
为什么被折叠?



