题解 | #染色#
染色
https://www.nowcoder.com/practice/fb48f6284a0f4e198f0bf2a988f703f8
题目链接
题目描述
有 罐油漆,进行
次操作。每次操作将一个区间
内的所有油漆罐加入一种颜色(1-黄, 2-蓝, 3-红)。一种油漆罐的最终颜色由其包含的颜料集合决定。求所有操作结束后,最终颜色为绿色(恰好包含黄色和蓝色,不包含红色)的油漆罐数量。
解题思路
本题的本质是需要对多个区间进行更新操作,并最终查询每个位置的状态。由于涉及三种独立的颜色,我们可以将问题分解,分别追踪每一罐油漆是否含有黄、蓝、红三种颜料。
这是一个典型的区间更新问题。如果对每次操作都遍历区间 来更新状态,总时间复杂度会是
,在数据量较大时可能会超时。
更高效的方法是使用差分数组。因为三种颜料的添加是独立事件,我们可以为每种颜色维护一个独立的差分数组。
- 创建三个差分数组,分别对应黄、蓝、红三种颜色,我们称之为
diff_yellow
,diff_blue
,diff_red
,长度都为。
- 遍历
次操作。对于每次操作
(l, r, c)
:- 如果
c
是黄色(1),则在diff_yellow
上执行操作:diff_yellow[l]++
,diff_yellow[r+1]--
。 - 如果
c
是蓝色(2),则在diff_blue
上执行操作:diff_blue[l]++
,diff_blue[r+1]--
。 - 如果
c
是红色(3),则在diff_red
上执行操作:diff_red[l]++
,diff_red[r+1]--
。 这样,我们在的时间内记录了所有操作。
- 如果
- 操作记录完成后,我们需要还原每个油漆罐的状态。通过对每个差分数组求前缀和,就可以得到每个位置被对应颜色覆盖的次数。
count_yellow[i] = count_yellow[i-1] + diff_yellow[i]
count_blue[i] = count_blue[i-1] + diff_blue[i]
count_red[i] = count_red[i-1] + diff_red[i]
如果count_color[i] > 0
,则说明第罐油漆含有该种颜色的颜料。这个过程的时间复杂度是
。
- 最后,我们遍历从 1 到
的所有油漆罐。根据题意,如果一个油漆罐
i
的最终颜色是绿色,当且仅当它含有黄色和蓝色颜料,且不含有红色颜料。即:count_yellow[i] > 0
且count_blue[i] > 0
且count_red[i] == 0
。 我们统计满足这个条件的油漆罐数量即可。这个过程的时间复杂度是。
综上,该算法的总时间复杂度为 ,可以高效地解决本题。
代码
#include <iostream>
#include <vector>
using namespace std;
int main() {
ios::sync_with_stdio(false);
cin.tie(NULL);
int n, m;
cin >> n >> m;
// 为黄(0), 蓝(1), 红(2) 三种颜色创建差分数组
vector<vector<int>> diff(3, vector<int>(n + 2, 0));
for (int i = 0; i < m; ++i) {
int l, r, c;
cin >> l >> r >> c;
// 颜色编号 c (1,2,3) 对应数组下标 (0,1,2)
diff[c - 1][l]++;
diff[c - 1][r + 1]--;
}
// 记录每罐油漆含有的颜色种类数
vector<int> yellow_count(n + 1, 0);
vector<int> blue_count(n + 1, 0);
vector<int> red_count(n + 1, 0);
// 计算黄色的覆盖情况
for (int i = 1; i <= n; ++i) {
diff[0][i] += diff[0][i - 1];
if (diff[0][i] > 0) yellow_count[i] = 1;
}
// 计算蓝色的覆盖情况
for (int i = 1; i <= n; ++i) {
diff[1][i] += diff[1][i - 1];
if (diff[1][i] > 0) blue_count[i] = 1;
}
// 计算红色的覆盖情况
for (int i = 1; i <= n; ++i) {
diff[2][i] += diff[2][i - 1];
if (diff[2][i] > 0) red_count[i] = 1;
}
int green_count = 0;
// 统计绿色油漆罐的数量
for (int i = 1; i <= n; ++i) {
if (yellow_count[i] > 0 && blue_count[i] > 0 && red_count[i] == 0) {
green_count++;
}
}
cout << green_count << "\n";
return 0;
}
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.StreamTokenizer;
import java.io.IOException;
public class Main {
public static void main(String[] args) throws IOException {
StreamTokenizer in = new StreamTokenizer(new BufferedReader(new InputStreamReader(System.in)));
in.nextToken();
int n = (int) in.nval;
in.nextToken();
int m = (int) in.nval;
// 为黄(0), 蓝(1), 红(2) 三种颜色创建差分数组
int[][] diff = new int[3][n + 2];
for (int i = 0; i < m; i++) {
in.nextToken();
int l = (int) in.nval;
in.nextToken();
int r = (int) in.nval;
in.nextToken();
int c = (int) in.nval;
// 颜色编号 c (1,2,3) 对应数组下标 (0,1,2)
diff[c - 1][l]++;
diff[c - 1][r + 1]--;
}
boolean[] hasYellow = new boolean[n + 1];
boolean[] hasBlue = new boolean[n + 1];
boolean[] hasRed = new boolean[n + 1];
// 计算黄色的覆盖情况
int currentYellow = 0;
for (int i = 1; i <= n; i++) {
currentYellow += diff[0][i];
if (currentYellow > 0) hasYellow[i] = true;
}
// 计算蓝色的覆盖情况
int currentBlue = 0;
for (int i = 1; i <= n; i++) {
currentBlue += diff[1][i];
if (currentBlue > 0) hasBlue[i] = true;
}
// 计算红色的覆盖情况
int currentRed = 0;
for (int i = 1; i <= n; i++) {
currentRed += diff[2][i];
if (currentRed > 0) hasRed[i] = true;
}
int greenCount = 0;
// 统计绿色油漆罐的数量
for (int i = 1; i <= n; i++) {
if (hasYellow[i] && hasBlue[i] && !hasRed[i]) {
greenCount++;
}
}
System.out.println(greenCount);
}
}
import sys
# 快速输入
input = sys.stdin.readline
def solve():
n, m = map(int, input().split())
# 为黄(0), 蓝(1), 红(2) 三种颜色创建差分数组
diff = [[0] * (n + 2) for _ in range(3)]
for _ in range(m):
l, r, c = map(int, input().split())
# 颜色编号 c (1,2,3) 对应数组下标 (0,1,2)
diff[c - 1][l] += 1
diff[c - 1][r + 1] -= 1
has_yellow = [False] * (n + 1)
has_blue = [False] * (n + 1)
has_red = [False] * (n + 1)
# 计算黄色的覆盖情况
current_yellow = 0
for i in range(1, n + 1):
current_yellow += diff[0][i]
if current_yellow > 0:
has_yellow[i] = True
# 计算蓝色的覆盖情况
current_blue = 0
for i in range(1, n + 1):
current_blue += diff[1][i]
if current_blue > 0:
has_blue[i] = True
# 计算红色的覆盖情况
current_red = 0
for i in range(1, n + 1):
current_red += diff[2][i]
if current_red > 0:
has_red[i] = True
green_count = 0
# 统计绿色油漆罐的数量
for i in range(1, n + 1):
if has_yellow[i] and has_blue[i] and not has_red[i]:
green_count += 1
print(green_count)
solve()
算法及复杂度
- 算法:差分数组
- 时间复杂度:处理所有操作需要
,还原三种颜色的状态需要
,最后统计数量需要
。因此,总时间复杂度为
。
- 空间复杂度:需要三个差分数组来存储状态,因此空间复杂度为
。