题解 | #染色#

染色

https://www.nowcoder.com/practice/fb48f6284a0f4e198f0bf2a988f703f8

题目链接

染色

题目描述

罐油漆,进行 次操作。每次操作将一个区间 内的所有油漆罐加入一种颜色(1-黄, 2-蓝, 3-红)。一种油漆罐的最终颜色由其包含的颜料集合决定。求所有操作结束后,最终颜色为绿色(恰好包含黄色和蓝色,不包含红色)的油漆罐数量。

解题思路

本题的本质是需要对多个区间进行更新操作,并最终查询每个位置的状态。由于涉及三种独立的颜色,我们可以将问题分解,分别追踪每一罐油漆是否含有黄、蓝、红三种颜料。

这是一个典型的区间更新问题。如果对每次操作都遍历区间 来更新状态,总时间复杂度会是 ,在数据量较大时可能会超时。

更高效的方法是使用差分数组。因为三种颜料的添加是独立事件,我们可以为每种颜色维护一个独立的差分数组。

  1. 创建三个差分数组,分别对应黄、蓝、红三种颜色,我们称之为 diff_yellow, diff_blue, diff_red,长度都为
  2. 遍历 次操作。对于每次操作 (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]--。 这样,我们在 的时间内记录了所有操作。
  3. 操作记录完成后,我们需要还原每个油漆罐的状态。通过对每个差分数组求前缀和,就可以得到每个位置被对应颜色覆盖的次数。
    • 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,则说明第 罐油漆含有该种颜色的颜料。这个过程的时间复杂度是
  4. 最后,我们遍历从 1 到 的所有油漆罐。根据题意,如果一个油漆罐 i 的最终颜色是绿色,当且仅当它含有黄色和蓝色颜料,且不含有红色颜料。即: count_yellow[i] > 0count_blue[i] > 0count_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()

算法及复杂度

  • 算法:差分数组
  • 时间复杂度:处理所有操作需要 ,还原三种颜色的状态需要 ,最后统计数量需要 。因此,总时间复杂度为
  • 空间复杂度:需要三个差分数组来存储状态,因此空间复杂度为
全部评论

相关推荐

点赞 评论 收藏
分享
评论
点赞
收藏
分享

创作者周榜

更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务