题解:AtCoder AT_awc0048_c Streetlights and Blizzard

【题目来源】

AtCoder:C - Streetlights and Blizzard

【题目描述】

Takahashi is the manager of a city. Along the main street, \(N\) street lights are lined up in a row, numbered from left to right as street light \(1\), street light \(2\), \(\ldots\), street light \(N\). The initial durability of street light \(i\) (\(1 \leq i \leq N\)) is \(H_i\). A street light whose durability becomes \(0\) or less is considered to have collapsed.
高桥是一个城市的市长。沿着主干道,\(N\) 盏路灯排成一行,从左到右编号为路灯 \(1\)、路灯 \(2\)、……、路灯 \(N\)。路灯 \(i\)\(1 \leq i \leq N\))的初始耐久度为 \(H_i\)。耐久度降为 \(0\) 或以下的路灯被认为已倒塌。

This winter, \(M\) blizzards will come. The \(j\)-th blizzard (\(1 \leq j \leq M\)) decreases the durability of all street lights in the range from street light \(L_j\) to street light \(R_j\) by \(D_j\).
今年冬天,将有 \(M\) 场暴风雪。第 \(j\) 场暴风雪(\(1 \leq j \leq M\))会使从路灯 \(L_j\) 到路灯 \(R_j\) 范围内所有路灯的耐久度减少 \(D_j\)

The final durability of each street light is its initial durability minus the total decrease from all blizzards. That is, even if a street light's durability becomes \(0\) or less partway through, it is not exempt from the decreases caused by subsequent blizzards.
每盏路灯的最终耐久度为其初始耐久度减去所有暴风雪造成的总减少量。也就是说,即使某盏路灯的耐久度在中途变为 \(0\) 或以下,它仍会受后续暴风雪造成的减少影响。

After all blizzards have passed, determine the number of street lights whose final durability is \(1\) or more (i.e., that have not collapsed).
在所有暴风雪过后,确定最终耐久度大于等于 \(1\) 的路灯数量(即未倒塌的路灯数量)。

【输入】

\(N\) \(M\)
\(H_1\) \(H_2\) \(\ldots\) \(H_N\)
\(L_1\) \(R_1\) \(D_1\)
\(L_2\) \(R_2\) \(D_2\)
\(\vdots\)
\(L_M\) \(R_M\) \(D_M\)

  • The first line contains the number of street lights \(N\) and the number of blizzards \(M\), separated by a space.
  • The second line contains the initial durabilities \(H_1, H_2, \ldots, H_N\) of each street light, separated by spaces.
  • The following \(M\) lines provide information about each blizzard. The \(j\)-th line contains the left endpoint \(L_j\), right endpoint \(R_j\) of the range affected by the \(j\)-th blizzard, and the durability decrease \(D_j\), separated by spaces.

【输出】

Print in one line the number of street lights whose final durability is \(1\) or more after all blizzards have passed.

【输入样例】

5 2
10 5 8 3 7
2 4 3
1 3 4

【输出样例】

3

【核心思想】

  1. 问题分析:给定 \(N\) 盏路灯的初始耐久度 \(H_i\),以及 \(M\) 场暴风雪,每场暴风雪将区间 \([L_j, R_j]\) 内所有路灯耐久度减少 \(D_j\)。求最终耐久度 \(\geq 1\) 的路灯数量。这是一个差分数组 + 前缀和问题,关键在于高效处理大量区间减法操作。

  2. 算法选择

    • 差分数组(Difference Array):将 \(M\) 个区间减法操作转化为 \(2M\) 个单点更新,实现 \(O(1)\) 区间标记
    • 前缀和还原:通过一次前缀和遍历,将差分数组还原为每个位置的实际减少量
    • 离线处理:先记录所有操作,最后统一计算结果
  3. 关键步骤

    • 初始化:读取 \(N\)(路灯数量)、\(M\)(暴风雪数量)、\(H[1..N]\)(初始耐久度)
    • 差分标记(处理 \(M\) 个暴风雪):
      • 对于每个暴风雪 \((L_j, R_j, D_j)\)
        • a[L_j] -= D_j:在左边界减去 \(D_j\)
        • a[R_j + 1] += D_j:在右边界后一个位置加回 \(D_j\)(恢复后续位置)
    • 前缀和还原(计算每个位置的总减少量):
      • 遍历 \(i\)\(1\)\(N\)a[i] += a[i-1]
      • 此时 a[i] 表示路灯 \(i\) 受到的所有暴风雪的总减少量
    • 统计答案
      • 遍历 \(i\)\(1\)\(N\)
        • 计算最终耐久度:final = H[i] + a[i](注意 \(a[i]\) 为负数)
        • final >= 1,则 ans++
    • 输出答案 \(ans\)
  4. 时间/空间复杂度

    • 时间复杂度:\(O(N + M)\),差分标记 \(O(M)\),前缀和还原 \(O(N)\),统计答案 \(O(N)\)
    • 空间复杂度:\(O(N)\),差分数组和初始值数组
  5. 差分数组与前缀和的核心思想

    • 区间操作降维:差分数组将区间 \([l, r]\) 的减 \(D\) 操作转化为 a[l] -= D 和 `a[r+1] += D$,实现 \(O(1)\) 区间标记
    • 前缀和还原:通过前缀和将差分数组还原为实际值,a[i] 表示位置 \(i\) 的累计变化量
    • 离线处理优势:先记录所有操作,最后统一计算,避免重复遍历
    • 边界处理技巧:在 \(R_j + 1\) 处加回 \(D_j\),确保只有区间内的位置受到影响
    • 适用于区间加减、区间更新、离线查询类问题

【算法标签】

差分

【代码详解】

#include <bits/stdc++.h>
using namespace std;
#define int long long
const int N = 200005;
int n, m, ans;  // n: 位置数量, m: 操作次数, ans: 答案
int h[N], a[N]; // h: 初始值数组, a: 差分数组

signed main()
{
    // 读取n和m
    cin >> n >> m;

    // 读取初始值h[1..n]
    for (int i = 1; i <= n; i++)
    {
        cin >> h[i];
    }

    // 处理m个操作
    for (int i = 1; i <= m; i++)
    {
        int l, r, d;  // 区间[l, r]和变化值d
        cin >> l >> r >> d;

        // 差分操作
        a[l] -= d;     // 在左边界减去d
        a[r + 1] += d; // 在右边界+1处加回d
    }

    // 通过前缀和计算每个位置的变化值
    for (int i = 1; i <= n; i++)
    {
        a[i] += a[i - 1];  // a[i]现在表示位置i的总变化量
    }

    // 统计满足条件的元素个数
    for (int i = 1; i <= n; i++)
    {
        // 判断最终值是否≥1
        if ((h[i] + a[i]) >= 1)
        {
            ans++;
        }
    }

    // 输出结果
    cout << ans << endl;
    return 0;
}

【运行结果】

5 2
10 5 8 3 7
2 4 3
1 3 4
3
posted @ 2026-06-14 10:43  团爸讲算法  阅读(9)  评论(0)    收藏  举报