题解:AtCoder AT_awc0026_d Repainted Wall
【题目来源】
AtCoder:D - Repainted Wall
【题目描述】
Takahashi is painting a long horizontal wall with paint.
高桥正在用油漆粉刷一堵长长的水平墙壁。
The wall extends across the entire number line, and initially, every point on the number line has been painted \(0\) times. Takahashi performed \(N\) painting operations. In the \(i\)-th operation \((1 \leq i \leq N)\), he painted the interval \([L_i, R_i]\) (where \(L_i < R_i\)) once. That is, for every point corresponding to a real number \(x\) satisfying \(L_i \leq x \leq R_i\), the number of times it has been painted increased by \(1\).
这面墙覆盖了整个数轴,初始时,数轴上的每个点都被粉刷了 \(0\) 次。高桥进行了 \(N\) 次粉刷操作。在第 \(i\) 次操作(\(1 \leq i \leq N\))中,他粉刷了区间 \([L_i, R_i]\)(其中 \(L_i < R_i\))一次。也就是说,对于每个满足 \(L_i \leq x \leq R_i\) 的实数 \(x\) 对应的点,其被粉刷的次数增加了 \(1\)。
Parts that have been painted \(K\) or more times are considered sufficiently thick and pass inspection, while parts painted fewer than \(K\) times are too thin and fail.
被粉刷 \(K\) 次或更多次的区域被认为是足够厚的并通过检查,而被粉刷少于 \(K\) 次的区域则太薄而未通过。
After all operations are completed, find the total length of the set of all points that have been painted \(K\) or more times (that is, the sum of the lengths of each interval that constitutes this set).
在所有操作完成后,求被粉刷 \(K\) 次或更多次的所有点组成的集合的总长度(即构成该集合的每个区间长度之和)。
For example, if the set of all points painted \(K\) or more times is the union of intervals \([1, 5]\) and \([7, 9]\), the answer is \((5 - 1) + (9 - 7) = 6\).
例如,如果被粉刷 \(K\) 次或更多次的所有点组成的集合是区间 \([1, 5]\) 和 \([7, 9]\) 的并集,则答案为 \((5 - 1) + (9 - 7) = 6\)。
Note that since all \(L_i\) and \(R_i\) are integers, the boundaries where the paint count changes occur only at integer coordinates. Therefore, the answer is always an integer.
注意,由于所有 \(L_i\) 和 \(R_i\) 都是整数,油漆次数变化的边界仅出现在整数坐标处。因此,答案总是一个整数。
【输入】
\(N\) \(K\)
\(L_1\) \(R_1\)
\(L_2\) \(R_2\)
\(\vdots\)
\(L_N\) \(R_N\)
- The first line contains an integer \(N\) representing the number of painting operations and an integer \(K\) representing the threshold number of coats required to pass inspection, separated by a space.
- The \(i\)-th of the following \(N\) lines \((1 \leq i \leq N)\) contains the left endpoint \(L_i\) and right endpoint \(R_i\) of the interval painted in the \(i\)-th operation, separated by a space.
【输出】
Output the total length of the set of all points painted \(K\) or more times, as an integer on a single line.
【输入样例】
3 2
1 5
3 7
6 9
【输出样例】
3
【核心思想】
-
问题分析:给定 \(N\) 个区间粉刷操作,每次将区间 \([L_i, R_i]\) 的覆盖次数加 \(1\)。求最终被覆盖 \(K\) 次或以上的点的总长度。这是一个扫描线(Sweep Line)+ 差分问题,关键在于如何高效计算每个点的覆盖次数。
-
算法选择:
- 差分思想:在区间起点 \(L_i\) 处 \(+1\),在区间终点 \(R_i\) 处 \(-1\),将区间更新转化为单点更新
- 扫描线算法:按坐标从小到大遍历所有关键点,维护当前覆盖次数
- Map 有序存储:使用
map自动对坐标排序,避免手动离散化
-
关键步骤:
- 差分预处理:
- 对于每个区间 \([L_i, R_i]\):
mp[L_i]++:在起点处覆盖次数加 \(1\)mp[R_i]--:在终点处覆盖次数减 \(1\)
- 对于每个区间 \([L_i, R_i]\):
- 扫描线遍历(按坐标从小到大):
- 初始化
last = 0(上一个坐标),cnt = 0(当前覆盖次数) - 遍历
map中的每个关键点 \((pos, delta)\):- 累加有效区间长度:若
cnt >= K,则ans += pos - last,将区间 \([last, pos)\) 的长度加入答案 - 更新状态:
last = pos,cnt += delta
- 累加有效区间长度:若
- 初始化
- 输出总长度 \(ans\)
- 差分预处理:
-
时间/空间复杂度:
- 时间复杂度:\(O(N \log N)\),
map插入和遍历均为 \(O(\log N)\) - 空间复杂度:\(O(N)\),最多存储 \(2N\) 个不同的坐标点
- 时间复杂度:\(O(N \log N)\),
-
扫描线与差分的核心思想:
- 差分转化:将区间 \([l, r]\) 的加 \(1\) 操作转化为
diff[l]++和diff[r]--,实现 \(O(1)\) 区间标记 - 扫描线维护:按坐标顺序遍历,用变量
cnt维护当前位置的覆盖次数(前缀和) - 区间贡献计算:当
cnt >= K时,当前扫描的区间 \([last, pos)\) 对答案有贡献 - 离散化简化:使用
map自动去重和排序,避免复杂的手动离散化 - 适用于区间覆盖统计、面积并集、扫描线类几何问题
- 差分转化:将区间 \([l, r]\) 的加 \(1\) 操作转化为
【解题思路】

【算法标签】
差分
【代码详解】
#include <bits/stdc++.h>
using namespace std;
const int N = 200005;
int n, k, ans, cnt; // n: 区间数量,k: 阈值,ans: 总长度,cnt: 当前覆盖次数
map<int, int> mp; // 差分映射:key为坐标,value为变化量
int main()
{
cin >> n >> k; // 读入区间数量和阈值
for (int i = 1; i <= n; i++) // 处理每个区间
{
int l, r;
cin >> l >> r; // 读入区间左端点和右端点
mp[l]++; // 在l处进入区间,覆盖次数+1
mp[r]--; // 在r处离开区间,覆盖次数-1
}
int last = 0, cnt = 0; // last: 上一个坐标点,cnt: 当前覆盖次数
// 扫描线遍历所有关键点
for (auto x : mp) // 按坐标从小到大遍历
{
int pos = x.first; // 当前坐标
int delta = x.second; // 覆盖次数的变化量
if (cnt >= k) // 如果上一个区间的覆盖次数≥k
{
// 累加上一个区间[last, pos)的长度
ans += pos - last;
}
last = pos; // 更新上一个坐标
cnt += delta; // 更新当前覆盖次数
}
cout << ans << endl; // 输出总长度
return 0;
}
【运行结果】
3 2
1 5
3 7
6 9
3
浙公网安备 33010602011771号