蓝桥杯·全国青少年信息素养大赛·电子学会Python/C++考级:差分数组与区间修改实战解析

备赛季到了!第十八届蓝桥杯软件赛(C/C++ 程序设计、Python 程序设计)报名 2026-10-08---12-18,省赛定于 2027-04-10;中国电子学会 2026 年 12 月软件编程(C/C++ 一至十级、Python 一至六级)等级考试报名 9/23--12/2,12/12--12/13 统考。这类赛事的算法题里,"给一段区间统一加减"是高频送分又容易翻车的考点------今天用一篇把它讲透。

一、引言:为什么需要差分数组

假设你负责校园里一排路灯的亮度调度。一开始每盏灯有基础亮度,接下来后勤处会反复下达指令:"把第 3 到第 7 盏灯整体调亮 5 度""把第 5 到第 9 盏灯调暗 2 度"......最后你要报出每盏灯的最终亮度,以及全场最亮的灯是哪盏。

最朴素的写法:每条指令都真的去循环修改区间里的每一盏灯。如果灯有 n 盏、指令有 m 条,总时间就是 O(n·m)。当 n、m 都到 10⁵ 量级时,这个做法一定会超时。

差分数组(Difference Array) 就是专门对付"区间整体加/减"的利器:它把每次"区间加"压成两个端点的 O(1) 操作,最后用一次前缀和还原,总时间降到 O(n + m)。这正是蓝桥杯省赛、电子学会 C/C++ 与 Python 考级(三/四级往上)、全国青少年信息素养大赛算法应用赛项里反复出现的套路。


二、题目 / 项目目标

【原创题】校园路灯调光

  • 校园里有 n 盏路灯,编号 1 ~ n,初始亮度为 a[1..n](整数,可为 0)。
  • 接下来有 m 次调度指令,第 i 次把区间 [l, r] 内的每盏灯亮度统一加上 v(v 可以是负数,表示调暗)。
  • 请计算:
  • 每盏路灯的最终亮度;
  • 全程亮度最高的那盏灯的亮度值与编号。

数据范围(蓝桥杯风格) :1 ≤ n, m ≤ 10⁵,亮度与增量均为 int 范围内整数,但多次累加后可能超出 int,请用 64 位整数(long long / Python int)。

样例输入

复制代码
5 4
0 0 0 0 0
1 3 2
2 4 3
3 3 -1
2 5 1

样例输出

复制代码
2 6 5 4 1
max brightness = 6 at 2

(第 2 盏灯最终最亮,亮度为 6)


三、核心考点

  1. 差分的定义与性质 :对数组 a,差分数组 d[i] = a[i] - a[i-1](约定 a[0] = 0)。d 的前缀和恰好还原 a;反过来 a 的差分再前缀和还是 a------两者互逆。
  2. 区间加 → 两点改 :对 a 的区间 [l, r] 整体加 v,等价于只改 d 的两个位置:d[l] += v、d[r+1] -= v。其余位置的差分不变,因此单条指令从 O(区间长度) 降到 O(1)。
  3. 前缀和还原 :处理完所有指令后,a[i] = a[i-1] + d[i] 从前往后扫一遍即可还原最终数组,同时可顺手维护最大值。
  4. 边界与下标 :r+1 最大会到 n+1,数组要开到 n+2 才安全;下标体系(1-based / 0-based)必须全程统一。
  5. 带初值的处理 :若初始就有基础亮度 a,别把 a 直接当差分,而要先把它"差分化"再叠加区间操作(见下方代码)。

四、解法 / 拆解

思路拆解

  • 第 0 步:根据初始亮度 a 构造差分数组 d:d[1] = a[1],d[i] = a[i] - a[i-1](i ≥ 2)。
  • 第 1 步(m 次区间加):对每条指令 [l, r, v],执行 d[l] += v; d[r+1] -= v。这一步每条 O(1)。
  • 第 2 步(前缀和还原 + 求最值):cur 从 0 开始,cur += d[i] 即 a[i],边还原边记录最大值与位置。
  • 复杂度:构造 O(n) + 修改 O(m) + 还原 O(n) = O(n + m);空间 O(n)。

C++ 解法

cpp 复制代码
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;

int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    int n, m;
    if (!(cin >> n >> m)) return 0;
    vector<long long> base(n + 2, 0);
    for (int i = 1; i <= n; i++) cin >> base[i];

    // 1) 把初始亮度"差分"进 d 数组
    vector<long long> d(n + 2, 0);
    d[1] = base[1];
    for (int i = 2; i <= n; i++) d[i] = base[i] - base[i - 1];

    // 2) m 次区间加,每条 O(1)
    for (int i = 0; i < m; i++) {
        int l, r; long long v;
        cin >> l >> r >> v;
        d[l] += v;
        d[r + 1] -= v;          // r+1 最多到 n+1,数组开到 n+2 才不越界
    }

    // 3) 前缀和还原,同时求最大值
    long long cur = 0, mx = -1e18; int mxpos = 0;
    for (int i = 1; i <= n; i++) {
        cur += d[i];
        if (cur > mx) { mx = cur; mxpos = i; }
        cout << cur << (i == n ? "" : " ");
    }
    cout << "\nmax brightness = " << mx << " at " << mxpos << "\n";
    return 0;
}

Python 解法

python 复制代码
import sys

def solve():
    data = sys.stdin.read().split()
    if not data:
        return
    it = iter(data)
    n = int(next(it)); m = int(next(it))
    base = [0] + [int(next(it)) for _ in range(n)]

    # 1) 把初始亮度差分进 d 数组
    d = [0] * (n + 2)
    d[1] = base[1]
    for i in range(2, n + 1):
        d[i] = base[i] - base[i - 1]

    # 2) m 次区间加,每条 O(1)
    for _ in range(m):
        l = int(next(it)); r = int(next(it)); v = int(next(it))
        d[l] += v
        d[r + 1] -= v

    # 3) 前缀和还原,同时求最大值
    cur = 0; mx = -10**18; mxpos = 0
    out = []
    for i in range(1, n + 1):
        cur += d[i]
        if cur > mx:
            mx = cur; mxpos = i
        out.append(str(cur))
    print(" ".join(out))
    print(f"max brightness = {mx} at {mxpos}")

if __name__ == "__main__":
    solve()

两个版本对样例均输出 2 6 5 4 1 与 max brightness = 6 at 2,与手算一致。


五、进阶

1. 二维差分(矩阵子矩形整体加)

把一行扩展成网格:想把以 (x1, y1) 为左上、(x2, y2) 为右下的矩形整体加 v,只需四个角做 O(1) 标记:

复制代码
d[x1][y1]     += v
d[x1][y2+1]   -= v
d[x2+1][y1]   -= v
d[x2+1][y2+1] += v

最后做二维前缀和还原。这是蓝桥杯"填空/涂色/矩阵操作"题的常客。

2. 区间加 + 区间求和(二阶差分)

如果还要频繁查询"某段区间的和",一阶差分不够用了。思路是对差分数组再差分一次(二阶差分),或改用树状数组 / 线段树做区间加、区间求和。理解一阶差分是啃下这些数据结构的前置功。

3. 差分数组 = 离线一维扫描线

"区间加 1 / 减 1"的本质是扫描线:把所有区间左端点 +v、右端点之后 -v,从左到右扫一遍前缀和,就得到每个位置被覆盖的次数。经典应用:会议室冲突数、天数重叠统计、至少被 k 个区间覆盖的最大长度。

4. 与"前缀和"对照记忆(别混)

  • 前缀和 :擅长"区间求和转单点查"(用 S[r] - S[l-1])。

  • 差分 :擅长"区间加转变点改"(用 d[l]+=v, d[r+1]-=v)。

两者是一对互逆操作,经常在同一道题里配合使用(例如先差分做区间加,再前缀和还原后做区间求和)。


六、小结与互动

差分数组是"用空间换时间、用端点代替区间"思想的典型代表:把每次 O(区间长度) 的修改压缩成 O(1) 的两个端点操作,最后用一次 O(n) 前缀和收尾。它常出现在蓝桥杯省赛填空与编程大题、电子学会 C/C++ 与 Python 考级(三/四级往上)、全国青少年信息素养大赛算法应用赛项中,属于"性价比极高"的基础必会算法。

易错点速记(考前必看)

  1. r+1 越界:数组至少开到 n+2,否则最后一个区间会写爆边界。

  2. 下标不统一:区间用 1-based 但数组 0-based,整体错一位。

  3. 忘记前缀和还原,直接把 d 当答案输出。

  4. 带初值时差分初值算错:应是 d[1]=a[1]、d[i]=a[i]-a[i-1],不是 d[i]=a[i]。

  5. 把"区间加"误用前缀和、把"区间求和"误用差分------二者方向正好相反。

  6. 多组数据没把 d 和 cur/mx 彻底重置。

  7. 累加溢出:用 long long(C++)或放心用 Python int,别用 32 位 int 硬扛。

练一练:如果把题目改成"求最终数组里等于某个值 k 的元素个数",或"求被至少 2 条指令覆盖过的灯的数量",你会怎么用差分快速得到?欢迎在评论区贴出你的思路或代码,我们一起交流避坑!

觉得有用就点个赞 + 收藏,备赛季不迷路;关注我,持续更新蓝桥杯 / 电子学会考级 / 信息素养大赛算法干货。


📚 免费少儿编程资料(夸克网盘领取)

以下资料来自夸克网盘分享,点击链接可直接保存;若需在 App 内打开,也可复制下方明文链接:

  1. 全国青少年信息素养大赛复赛集训题目Python&C++.docx
    https://pan.quark.cn/s/93995d3cb150
  2. 2024信息素养-智能算法应用挑战赛-复赛初中组题目7月7日.pdf
    https://pan.quark.cn/s/da97b5dbf75d
  3. Python背记手册.pdf
    https://pan.quark.cn/s/7568ae9ca92b
  4. Python课程
    https://pan.quark.cn/s/a94bf02d00c6
  5. 2024信息素养大赛图形化复赛集训题答案3-9
    https://pan.quark.cn/s/6ccab7ec3cbc
  6. 2025年03月份电子学会考级真题
    https://pan.quark.cn/s/4403c4228912
  7. 2025全国青少年信息素养大赛赛项说明
    https://pan.quark.cn/s/d9d0df4a9f29
  8. 青少儿信息素养大赛编程资料
    https://pan.quark.cn/s/4ab6bd83be8a

资料持续更新,关注获取最新分享。

相关推荐
重生之小比特1 小时前
【算法拾光】二分查找|二分查找 + 再排序数组中查找元素的第一个和最后一个位置
算法·leetcode·职场和发展
小小张说故事1 小时前
Python 的 sort 为什么又稳又快?拆开 Timsort:run 检测、minrun 与 galloping 的三板斧
python
纪念 2291 小时前
C++ list讲解
c++·windows·list
kaizq1 小时前
从照片开口说话实现到应用职业教培变革落地
python·应用职业教育·ai混元-元宝·数学学习基础·用中学-学中用·照片aigc-gif
OnlineProxy1 小时前
Python 高负载异步爬虫优化指南:深挖 httpx 与 aiohttp 的性能极限
爬虫·python·httpx
零基础1231 小时前
基于模型的强化学习与不基于模型的强化学习:核心区别与实战选择
python·算法
我命由我123451 小时前
5-2.Python 编码进阶 - 字符串进阶(拼接、普通格式化、普通格式化数字精度控制、快速格式化、遍历、常用方法)
java·开发语言·后端·python·学习·java-ee·学习方法
专业程序开发源1 小时前
django视听资源推荐系统16690-计算机课程设计、毕业设计
vue.js·spring boot·后端·python·django·php·课程设计
我的xiaodoujiao2 小时前
Django 权限系统项目实战详细图文教程 2--环境搭建
后端·python·django