【数据结构】开关

145 阅读2分钟

携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第27天,点击查看活动详情

[TJOI2009] 开关

题目描述

现有 nn 盏灯排成一排,从左到右依次编号为:1122,……,nn。然后依次执行 mm 项操作。

操作分为两种:

  1. 指定一个区间 [a,b][a,b],然后改变编号在这个区间内的灯的状态(把开着的灯关上,关着的灯打开);
  2. 指定一个区间 [a,b][a,b],要求你输出这个区间内有多少盏灯是打开的。

灯在初始时都是关着的。

输入格式

第一行有两个整数 nnmm,分别表示灯的数目和操作的数目。

接下来有 mm 行,每行有三个整数,依次为:ccaabb。其中 cc 表示操作的种类。

  • cc 的值为 00 时,表示是第一种操作。
  • cc 的值为 11 时,表示是第二种操作。

aabb 则分别表示了操作区间的左右边界。

输出格式

每当遇到第二种操作时,输出一行,包含一个整数,表示此时在查询的区间中打开的灯的数目。

样例 #1

样例输入 #1

4 5
0 1 2
0 2 4
1 2 3
0 2 4
1 1 4

样例输出 #1

1
2

提示

数据规模与约定

对于全部的测试点,保证 2n1052\le n\le 10^51m1051\le m\le 10^51a,bn1\le a,b\le nc{0,1}c\in\{0,1\}

#include <bits/stdc++.h>
#define SIZE 1000030
using namespace std;

struct SegmentTree {
	int l, r;
	int l0, l1, add; 
    // l0 表示 关着的灯的数量, 
    // l1 表示 亮着的灯的数量 
} t[SIZE * 4];
int n, m, opt, x, y;

void build(int p, int l, int r) {//建树 
	t[p].l = l;    t[p].r = r;
	if (l == r) {
		t[p].l0++;
		return ;
	}
	int mid = (l + r) / 2;
	build(p<<1, l, mid); 
	build(p<<1|1, mid + 1, r);
	t[p].l0 = t[p<<1].l0 + t[p<<1|1].l0;
}
inline void spread(int p) {//打标记 
	if (t[p].add == 0) return ;
	swap(t[p<<1].l0, t[p<<1].l1);  //交换
	swap(t[p<<1|1].l0, t[p<<1|1].l1);
	t[p<<1].add ^= 1;  //开关灯就相当于 ^ 一下 
	t[p<<1|1].add ^= 1;
	t[p].add = 0;
}
inline void change(int p, int l, int r) {
	//开关灯,线段树板子 
	if (t[p].l >= l && t[p].r <= r) {
		t[p].add ^= 1;
		swap(t[p].l0, t[p].l1);
		return ;
	}
	spread(p);
	int mid = (t[p].l + t[p].r) / 2;
	if (l <= mid) change(p<<1, l, r);
	if (mid < r) change(p<<1|1, l, r);
	t[p].l0 = t[p<<1].l0 + t[p<<1|1].l0;
	t[p].l1 = t[p<<1].l1 + t[p<<1|1].l1;
}
int ask(int p, int l, int r) { 
	//查询开着的灯的数量 
	if (t[p].l >= l && t[p].r <= r) 
		return t[p].l1;
	spread(p);
	int mid = (t[p].l + t[p].r) / 2, sum = 0;
	if (l <= mid) sum += ask(p<<1, l, r);
	if (mid < r) sum += ask(p<<1|1, l, r);
	return sum;
}
inline void solve() {
	scanf ("%d%d", &n, &m);
	build(1, 1, n);
	for (int i = 1; i <= m; ++i) {
		scanf ("%d%d%d", &opt, &x, &y);
		if (opt == 0) 
			change(1, x, y);
		else 
			printf("%d\n", ask(1, x, y));
	}
}
int main() {
	solve();
	return 0;
}