📅  最后修改于: 2023-12-03 15:28:48.280000             🧑  作者: Mango
本题为“门|门 IT 2006”竞赛中的一道编程题,是一道典型的模拟题。该题目涉及到对多个操作的模拟,对于初学者而言是一道不错的练习题目。
在一条线段上有 $n$ 个点$(1 \leq n \leq 100)$,初始时所有点的颜色都是黑色。有 $m$ 个操作$(1 \leq m \leq 100)$,操作分 $3$ 种类型:
请实现一个模拟程序,模拟 $m$ 个操作后的最终状态。
本题难点在于操作的模拟。对于翻转和变色操作,只需要用一个布尔型数组 $color$ 来记录每个点的颜色,然后在对应的区间内进行修改即可。对于统计黑点的个数,只需要遍历区间,统计颜色为黑的点的个数即可。
具体实现时,可以使用多种数据结构进行支持,例如线段树,树状数组等。以线段树为例,可以使用如下的思路:
Node
作为线段树节点,包含三个成员变量,分别是 $l,r$ 表示区间左右边界,$cnt$ 表示区间内黑色点的个数。buildTree
和 updateTree
,分别用于建立线段树和更新节点信息。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;
}
以上代码实现了线段树的建立和更新,以及统计黑色点的个数。其他的操作类似,可以根据具体的业务需求进行删减或扩展。