算法日记13:SC41树状数组(区间修改)

news/2025/2/9 1:23:09 标签: 算法

一、题目:

在这里插入图片描述

二、题解:

在单点修改中,我们用t[i]来维护原数组

2.1:在区间修改中,我们将维护原数组的差分数组

  • 接下来,让我们来回顾一些差分的性质
    在这里插入图片描述
  • 此时,假设我们需要求 a 1 + a 2 + a 3 + a 4 a1+a2+a3+a4 a1+a2+a3+a4的和,并且是直接通过 d [ i ] d[i] d[i]来求,我们可以发现:
    在这里插入图片描述
  • 推广到 n n n可以得到
    在这里插入图片描述

2.2:因此我们可以维护两个数组,一个为 t d [ i ] td[i] td[i](PS:因为n+1是常量),一个为 i ∗ t d [ i ] i*td[i] itd[i],这样就可以直接通过 d [ i ] d[i] d[i]来进行区间查询

  • t d [ i ] td[i] td[i]表示的是: d [ i ] d[i] d[i] [ i − l o w b i t ( i ) + 1 , i ] [i-lowbit(i)+1,i] [ilowbit(i)+1,i]的值(PS:相当于差分时,对差分数组做前缀和映射到原数组)
    在这里插入图片描述

2.3:相较于单点修改的差别

1、变量定义:

ll td[N];  //维护树状数组的差分
ll tdi[N]; //维护td[i]*i

2、更新树状数组–>更新树状差分数组单点修改(相当于在 i i i + a [ i ] +a[i] +a[i])

	//初始化树状差分数组
    for (int i = 1; i <= n; i++) 
    {
        update(i, a[i]);
        update(i+1,-a[i]);
    }

3、对于操作1(区间修改)变化:运用差分性质( ( a [ l ] − > a [ r ] ) + v = = ( d [ l ] + v ) , d [ r + 1 ] − v (a[l]->a[r])+v==(d[l]+v),d[r+1]-v (a[l]>a[r])+v==(d[l]+v),d[r+1]v)

		int op; cin >> op;
        if (op == 1)
        {
            ll l, r , v; cin >> l >> r >> v;
            update(l, v);   //维护差分数组
            update(r+1,-v);
        }

4、 u p d a t e ( ) update() update()更新函数的变化:

  • 1):与单点修改思路一致,差分数组( t d [ i ] td[i] td[i])对于其每一个数字的管辖区间 + v +v +v
  • 2):对于 t d i [ i ] tdi[i] tdi[i],也就是 i ∗ t d [ i ] i*td[i] itd[i],每一个元素都应该 + + +传入函数的原始值 ( x ∗ v ) (x*v) xv如图:而不应该 ( i ∗ v ) (i*v) (iv)因为此时 t d i [ x ] tdi[x] tdi[x]的增加影响了 t d i [ i ] tdi[i] tdi[i]的值如果写成了 ( i ∗ v ) (i*v) (iv)就变成了 ( 4 ∗ 2 ) (4*2) 42,但是实际应该为 ( 3 ∗ 2 ) (3*2) (32)
    在这里插入图片描述
void update(ll x, ll v)   //第 x 个值变化了 v
{
    for (int i = x; i <= n; i += lowbit(i))
    {
        td[i] += v; //维护td
        tdi[i]+=x*v; //维护td*i
    }
}

5、 g e t s u m ( ) getsum() getsum()求和函数的变化

  • 1、由推广公式可以得到求和函数
  • 2、类比前缀和的性质,求解 g e t s u m ( r ) − g e t s u m ( l − 1 ) getsum(r) - getsum(l - 1) getsum(r)getsum(l1)即可得出 [ l , r ] [l,r] [l,r]的和
    在这里插入图片描述
ll getsum(ll x)   //区间查询
{
    ll sum = 0;
    for (int i = x; i >= 1; i-=lowbit(i))
    {
        sum += (x+1)*td[i]-tdi[i];
    }
    return sum;
}
ll l, r; cin >> l >> r;
cout << getsum(r) - getsum(l - 1) << '\n';

三、完整代码如下:

#include <bits/stdc++.h>
using namespace std;

typedef long long ll;
const int N = 3e5 + 7;
ll a[N];
ll td[N];  //维护树状数组的差分
ll tdi[N]; //维护td[i]*i
ll n, q;

ll lowbit(ll x)   //树状数组底层函数
{
    return x & -x;
}

void update(ll x, ll v)   //第 x 个值变化了 v
{
    for (int i = x; i <= n; i += lowbit(i))
    {
        td[i] += v; //维护td
        tdi[i]+=x*v; //维护td*i
    }
}

ll getsum(ll x)   //区间查询
{
    ll sum = 0;
    for (int i = x; i >= 1; i-=lowbit(i))
    {
        sum += (x+1)*td[i]-tdi[i];	//求和公式
    }
    return sum;
}

void solve()
{
    cin >> n >> q ;
    for (int i = 1; i <= n; i++) cin >> a[i];

    //初始化树状数组
    for (int i = 1; i <= n; i++) 
    {
        update(i, a[i]);
        update(i+1,-a[i]);
    }
    while (q--) //q次询问
    {
        int op; cin >> op;
        if (op == 1)
        {
            ll l, r , v; cin >> l >> r >> v;
            update(l, v);   //维护差分数组
            update(r+1,-v);
        }
        else
        {
            ll l, r; cin >> l >> r;
            cout << getsum(r) - getsum(l - 1) << '\n';
        }
    }
}


int main() {
    ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
    int _ = 1; //cin >> _;
    while (_--) solve();
    system("pause");

    return 0;
}

http://www.niftyadmin.cn/n/5845423.html

相关文章

LeetCode:59. 螺旋矩阵 II(模拟 Java)

目录 59. 螺旋矩阵 II 题目描述&#xff1a; 实现代码与解析&#xff1a; 模拟 原理思路&#xff1a; 59. 螺旋矩阵 II 题目描述&#xff1a; 给你一个正整数 n &#xff0c;生成一个包含 1 到 n2 所有元素&#xff0c;且元素按顺时针顺序螺旋排列的 n x n 正方形矩阵 ma…

s1:简单测试-时间规模化

25年1月来自斯坦福、西雅图 UW、AI2 和 Contextual AI 的论文“s1: Simple test-time scaling”。 测试-时间规模化是一种很有前途的语言建模新方法&#xff0c;它使用额外的测试-时间计算来提高性能。最近&#xff0c;OpenAI 的 o1 模型展示这种能力&#xff0c;但并未公开分…

apisix的real-ip插件使用说明

k8s集群入口一般都需要过负载均衡&#xff0c;然后再到apisix。 这时候如果后台业务需要获取客户端ip&#xff0c;可能拿到的是lb或者网关的内网ip。 这里一般要获取真实ip需要做几个处理。 1. 负载均衡上&#xff0c;一般支持配置获取真实ip参数&#xff0c;需要配置上。然…

Cloudflare 2024 网络流量回顾:洞悉网络发展趋势与安全挑战

Cloudflare 近日发布了 2024 年网络流量回顾报告&#xff0c;为我们提供了宝贵的全球互联网流量数据。这份报告涵盖了 IPv4/IPv6 比例、HTTP 协议版本占比、API 客户端语言分布、浏览器市场份额以及机器人流量分析等多个方面&#xff0c;为我们理解当前网络发展趋势和安全挑战提…

profinet转ModbusTCP网关,助机器人“掀起”工业智能的惊涛骇浪

在现代汽车制造过程中&#xff0c;生产设备的精确控制与实时监测是确保产品质量和生产效率的关键。某汽车制造厂在其生产线上应用了可编程逻辑控制器&#xff08;PLC&#xff09;和压力传感器&#xff0c;这两种设备分别使用稳联技术Profinet和ModbusTCP协议&#xff08; WL-A…

linux——网络计算机{序列化及反序列化(JSON)(ifdef的用法)}

linux——网络&#xff08;服务器的永久不挂——守护进程&#xff09;-CSDN博客 目录 一、序列化与反序列化 1. 推荐 JSON 库 2. 使用 nlohmann/json 示例 安装方法 基础用法 输出结果 3. 常见操作 4. 其他库对比 5. 选择建议 二、ifdef宏的用法 基本语法 核心用途…

RabbitMQ 从入门到精通:从工作模式到集群部署实战(五)

#作者&#xff1a;闫乾苓 系列前几篇&#xff1a; 《RabbitMQ 从入门到精通&#xff1a;从工作模式到集群部署实战&#xff08;一&#xff09;》&#xff1a;link 《RabbitMQ 从入门到精通&#xff1a;从工作模式到集群部署实战&#xff08;二&#xff09;》&#xff1a; lin…

用pytorch实现一个简单的图片预测类别

前言&#xff1a; 在阅读本文之前&#xff0c;你需要了解Python&#xff0c;Pytorch&#xff0c;神经网络的一些基础知识&#xff0c;比如什么是数据集&#xff0c;什么是张量&#xff0c;什么是神经网络&#xff0c;如何简单使用tensorboard,DataLoader。 本次模型训练使用的是…