读完题目应该就能发现是一道线段树的板子题目。

这道题目共有两个操作:

  • 在一段区间内,把所有开的灯关了,再把关的灯打开。
  • 在一段区间内,求开的灯的个数

对于第一个操作,也就是 $0 \to 1,1 \to0$,是不是很容易想到 ^。我们可以开两个数组,一个用于维护开的灯,另一个维护关的灯,分别记为 tree1tree2
若有 $a$ 个灯是开的,$b$ 个灯是关的,则当进行操作一后,会有 $b$ 个灯是开的,$a$ 个灯是关的。也就是把 这两个数交换了一下。
因为是区间更新,所以还要配合着标记下传的使用。标记很简单,每次异或一下就行,但需要记得最后的标记清空操作。

对于第二个操作,也就是查询操作。我们只需要查询该区间内有关 tree2 的值即可。把区间内符合条件的数组进行累加,最后输出就完事了。


完整代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
#include <iostream>
#include <cstdio>
using namespace std;
const int MAX = 100005;
int temp[MAX << 2],n,m,tree1[MAX << 2],tree2[MAX << 2];
//tree1 维护关灯的数量,tree2 维护开灯的数量
void build (int cur,int l,int r);
void ch (int cur,int l,int r,int x,int y);
void pushdown (int cur);
int query (int cur,int l,int r,int x,int y);
int main ()
{
scanf ("%d%d",&n,&m);
build (1,1,n);
for (int i = 1;i <= m;++i)
{
int type;
scanf ("%d",&type);
if (type == 0)
{
int x,y;
scanf ("%d%d",&x,&y);
ch (1,1,n,x,y);
}
else
{
int x,y;
scanf ("%d%d",&x,&y);
printf ("%d\n",query (1,1,n,x,y));
}
}
return 0;
}
void build (int cur,int l,int r)
{
if (l == r)
{
tree1[cur]++;//同理 tree[cur] = 1
return ;
}
int mid = (l + r) >> 1;
build (cur << 1,l,mid);build (cur << 1 | 1,mid + 1,r);
tree1[cur] = tree1[cur << 1] + tree1[cur << 1 | 1];
}
void ch (int cur,int l,int r,int x,int y)
{
if (l >= x && r <= y)
{
temp[cur] ^= 1;//异或
swap (tree1[cur],tree2[cur]);//交换
return ;
}
int mid = (l + r) >> 1;
pushdown (cur);
if (x <= mid) ch (cur << 1,l,mid,x,y);
if (y > mid) ch (cur << 1 | 1,mid + 1,r,x,y);
tree1[cur] = tree1[cur << 1] + tree1[cur << 1 | 1];
tree2[cur] = tree2[cur << 1] + tree2[cur << 1 | 1];//同时更新
}
void pushdown (int cur)//标记下传
{
if (temp[cur] == 0) return ;
swap (tree1[cur << 1],tree2[cur << 1]);
swap (tree1[cur << 1 | 1],tree2[cur << 1 | 1]);//交换
temp[cur << 1] ^= 1,temp[cur << 1 | 1] ^= 1;//异或一下
temp[cur] = 0;//清空!!!
}
int query (int cur,int l,int r,int x,int y)
{
if (l >= x && r <= y) return tree2[cur];//注意返回 tree2 的值
int mid = (l + r) >> 1;
pushdown (cur);
int ans = 0;
if (x <= mid) ans += query (cur << 1,l,mid,x,y);
if (y > mid) ans += query (cur << 1 | 1,mid + 1,r,x,y);
return ans;
}