洛谷 P3870 [TJOI2009]开关

题意简述

有n盏灯,默认为关,有两个操作:
1.改变l~r的灯的状态(把开着的灯关上,关着的灯打开)
2.查询l~r开着的灯的数量

题解思路

维护一个线段树,支持区间修改,区间查询
懒标记每次^1

代码

#include <cstdio>
using namespace std;
int n, m, opt, x, y;
int a[400010], la[400010];
void push_up(int x)
{
	a[x] = a[x << 1] + a[x << 1 | 1];
}
void push_down(int x, int len)
{
	a[x << 1] = (len - (len >> 1)) - a[x << 1];
	a[x << 1 | 1] = (len >> 1) - a[x << 1 | 1];
	la[x << 1] ^= 1;
	la[x << 1 | 1] ^= 1;
	la[x] = 0;
}
void change(int x, int l, int r, int l1, int r1)
{
	if (l1 <= l && r <= r1)
	{
		a[x] = r - l + 1 - a[x];
		la[x] ^= 1;
		return;
	}
	if (la[x]) push_down(x, r - l + 1);
	int mid = l + r >> 1;
	if (l1 <= mid) change(x << 1, l, mid, l1, r1);
	if (r1 >  mid) change(x << 1 | 1, mid + 1, r, l1, r1);
	push_up(x); 
}
int query(int x, int l, int r, int l1, int r1, int ans = 0)
{
	if (l1 <= l && r <= r1)	return a[x];
	if (la[x]) push_down(x, r - l + 1);
	int mid = l + r >> 1;
	if (l1 <= mid) ans += query(x << 1, l, mid, l1, r1);
	if (r1 >  mid) ans += query(x << 1 | 1, mid + 1, r, l1, r1);
	return ans;
}
int main()
{
	scanf("%d%d", &n, &m);
	for (register int i = 1; i <= m; ++i)
	{
		scanf("%d", &opt);
		if (!opt)
		{
			scanf("%d%d", &x, &y);
			change(1, 1, n, x, y);
		}
		else
		{
			scanf("%d%d", &x, &y);
			printf("%d
", query(1, 1, n, x, y));
		}
	}
}
原文地址:https://www.cnblogs.com/xuyixuan/p/9477707.html