他这个的大致意思,我说一下,然后记得写一下代码
比如只考虑某个只有一个点的询问,在二维平面上查询区间 [ l , r ] [l,r] [l,r],值为 x x x
我们扫描线扫描到 l l l的时候,假设值为 x 0 x_0 x0, l + 1 l+1 l+1时,值为 x 1 x_1 x1,…, r r r时,值为 x r − l x_{r-l} xr−l,那么答案肯定就是所有 x x x加起来
假设 x i = d 0 + d i x_i=d_0+d_i xi=d0+di,那么答案就可以用 x 0 x_0 x0和 d d d表示,而 d i d_i di是 i i i位置前面所有修改的和,于是我们展开所有的 d d d,就会发现某个修改对答案的贡献就是这个修改的值乘以(这个询问的右端点减去这个修改的下标),即为这个修改的值乘以这个询问的右端点减去这个修改的值乘以这个修改的下标,所以我们用两次扫描,第一次将所有值乘以询问右端点,第二次将所有修改乘以询问的右端点就好了
答案见OI-wiki即可
主要是记住这个问题静态版本的解答方法,然后没必要用线段树,用树状数组就好了
可以像蓝书那样简化,把最开始的矩阵也变成一次一次的加的操作然后放到操作序列里面
update 2024.7.19
重新做的时候,一眼二维差分,然后就要上二维树状数组,结果真的可以这么做,而且正解就是这么做
提一个细节,在树状数组的修改/查询操作中的循环里面一定要定义临时变量,比如修改,要写成
void add(int x,int y,int d,int op)
{
for(int i=x;i<=n;i+=i&-i)
for(int j=y;j<=m;j+=j&-j)
c[i][j][op]+=d;
}
而不是
void add(int x,int y,int d,int op)
{
for(;x<=n;x+=x&-x)
for(;y<=m;y+=y&-y)
c[x][y][op]+=d;
}