前缀和和差分

前缀和是指某序列的前n项和,可以把它理解为数学上的数列的前n项和,而差分可以看成前缀和的逆运算。

前缀和

前缀和可以快速查找区间和

 

一维前缀和

for (int i = 1; i < n; i++)
{
    pre[i] = pre[i - 1] + a[i];//从一开始避免i-1越界
}

int ans=pre[R]-pre[L-1];//查询区间和

二维前缀和

for (int i = 1; i <= n; i++)
{
    for (int i = 1; i <= n; i++)
    {
        //前缀和的初始化
        pre[i][j] = pre[i][j - 1] + pre[i - 1][j] - pre[i - 1][j - 1] + a[i][j];
    }
}

//查询子矩阵和
int ans = pre[x2][y2] - pre[x2][y1 - 1] - pre[x1 - 1][y2] + pre[x1 - 1][y1 - 1];

差分

差分可以快速对区间进行增加或者减少

差分的前缀和是原数组,说明差分和前缀和是互逆操作

 

一维差分

初始化差分数组

for (int i = 1; i <= n; i++)
{
    //根据差分是原数组的前缀和推导出来
    diff[i] = a[i] - a[i - 1];
}

对于区间进行修改

void add(int L, int R, int value)
{
    diff[L] += value;
    diff[R + 1] -= value;//注意防止下标越界
}

一维差分可以根据差分是原数组的前缀和进行初始化,不过也可以不必纠结如何构造差分数组

初始化时,其实就是对差分数组进行增减的操作 我们也可以通过下面这种方式初始化差分数组

void add(int L, int R, int value)
{
    diff[L] += value;
    diff[R + 1] -= value;
}
for (int i=0; i < n; i++)
{
    //此时只需要差分数组的长度+1即可避免越界
    add(i, i, a[i]);
}

更新修改后的数据 即对差分数组进行前缀和

for (int i = 1; i <= n; i++)
{
    //要求下标从一开始,a[0]=0
    a[i] = a[i - 1] + diff[i];
}

二维差分

可以利用差分和前缀和的关系求递推式,也可使直接使用对差分数组增减的方式进行初始化

//差分数组的增减操作
void add(int x1, int y1, int x2, int y2, int value)
{
    diff[x1][y1] += value;
    diff[x2 + 1][y2 + 1] += value;
    diff[x2 + 1][y1] -= value;
    diff[x1][y2 + 1] -= value;
}
//初始化差分数组
for (int i = 0; i < n; i++)
{
    for (int j = 0; j < n; j++)
    {
        add(i, j, i, j, a[i][j]);
    }
}

同样的,对差分数组求前缀和就可以得到更新后的原数组

//对差分数组求二维前缀和
for (int i = 1; i <= n; i++)
{
    for (j = 1; j <= n; j++)
    {
        a[i][j] = a[i - 1][j] + a[i][j - 1] - a[i - 1][j - 1] + diff[i][j];
    }
}

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值