📜  门|门 IT 2006 |第 62 题(1)

📅  最后修改于: 2023-12-03 15:28:48.280000             🧑  作者: Mango

题目介绍

本题为“门|门 IT 2006”竞赛中的一道编程题,是一道典型的模拟题。该题目涉及到对多个操作的模拟,对于初学者而言是一道不错的练习题目。

题目描述

在一条线段上有 $n$ 个点$(1 \leq n \leq 100)$,初始时所有点的颜色都是黑色。有 $m$ 个操作$(1 \leq m \leq 100)$,操作分 $3$ 种类型:

  1. 翻转区间$(L,R)$,颜色由黑变白,由白变黑;
  2. 统计区间$(L,R)$ 中黑色点的个数;
  3. 将区间$(L,R)$ 中所有的点的颜色变成黑色。

请实现一个模拟程序,模拟 $m$ 个操作后的最终状态。

解题思路

本题难点在于操作的模拟。对于翻转和变色操作,只需要用一个布尔型数组 $color$ 来记录每个点的颜色,然后在对应的区间内进行修改即可。对于统计黑点的个数,只需要遍历区间,统计颜色为黑的点的个数即可。

具体实现时,可以使用多种数据结构进行支持,例如线段树,树状数组等。以线段树为例,可以使用如下的思路:

  1. 定义一个结构体 Node 作为线段树节点,包含三个成员变量,分别是 $l,r$ 表示区间左右边界,$cnt$ 表示区间内黑色点的个数。
  2. 定义一个静态数组 $tree$ 作为线段树的数组,每个节点的位置都对应线段树上的一个节点。
  3. 定义两个函数 buildTreeupdateTree,分别用于建立线段树和更新节点信息。
  4. 在主函数中,首先使用 buildTree 建立线段树,然后根据不同的操作执行对应的函数,最后输出操作结果。

代码示例

以下是基于C++11的代码示例,使用线段树进行模拟。

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>

using namespace std;

const int MAXN = 105;

struct Node{
    int l, r, cnt;
}tree[MAXN * 4];

int n, m;
bool color[MAXN];

void buildTree(int p, int l, int r)
{
    tree[p] = {l, r, 0};
    if(l == r)  return;
    int mid = (l + r) / 2;
    buildTree(p * 2, l, mid);
    buildTree(p * 2 + 1, mid + 1, r);
}

void updateTree(int p, int l, int r)
{
    if(tree[p].l >= l && tree[p].r <= r){
        tree[p].cnt = tree[p].r - tree[p].l + 1 - tree[p].cnt;
        return;
    }
    int mid = (tree[p].l + tree[p].r) / 2;
    if(l <= mid)    updateTree(p * 2, l, r);
    if(r > mid) updateTree(p * 2 + 1, l, r);
    tree[p].cnt = tree[p * 2].cnt + tree[p * 2 + 1].cnt;
}

int query(int p, int l, int r)
{
    if(tree[p].l >= l && tree[p].r <= r)    return tree[p].cnt;
    int mid = (tree[p].l + tree[p].r) / 2;
    int res = 0;
    if(l <= mid)    res += query(p * 2, l, r);
    if(r > mid) res += query(p * 2 + 1, l, r);
    return res;
}

int main()
{
    scanf("%d%d", &n, &m);
    memset(color, false, sizeof(color));
    buildTree(1, 1, n);
    for(int i = 1; i <= m; i++){
        int opt, l, r;
        scanf("%d%d%d", &opt, &l, &r);
        if(opt == 0){
            for(int j = l; j <= r; j++)
                color[j] = !color[j];
            updateTree(1, l, r);
        }
        else if(opt == 1){
            printf("%d\n", query(1, l, r));
        }
        else if(opt == 2){
            for(int j = l; j <= r; j++)
                color[j] = false;
            updateTree(1, l, r);
        }
    }
    return 0;
}

以上代码实现了线段树的建立和更新,以及统计黑色点的个数。其他的操作类似,可以根据具体的业务需求进行删减或扩展。