P3870 [TJOI2009] 开关

P3870 [TJOI2009] 开关_第1张图片

网址如下:

P3870 [TJOI2009] 开关 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)

看C艹书看不下去,就到洛谷上随机抽一道题做

一道线段树的问题

实际上,关于线段树的知识是我现学的(我树的知识都不知道,乐)

总结来说,比较重要的就是“懒标记”,加上传值和读取以及构建树的相应操作

算法学习网址如下:

算法学习笔记(14): 线段树 - 知乎 (zhihu.com)

第一次用,有点不熟悉,在读取的时候忘记更新mark(懒标记)了,导致刚开始只有10分

代码如下:

#include
using namespace std;
void update(int l, int r, int p, int cl, int cr);
int query(int l, int r, int p, int cl, int cr);
int tree[100000000], mark[100000000];
int n, m;

int main(void)
{
	//输入
	scanf("%d%d", &n, &m);
	//处理
	for(int i = 0; i < m; i++)
	{
		int n_tmp, l, r;
		scanf("%d%d%d", &n_tmp, &l, &r);
		if(n_tmp)
			printf("%d\n", query(l, r, 1, 1, n));
		else
			update(l, r, 1, 1, n);
	}

	return 0;
}
void update(int l, int r, int p, int cl, int cr)
{
	if(cl > r || cr < l)
		return;
	if(cl >= l && cr <= r)
	{
		tree[p] = (cr - cl + 1) - tree[p];
		mark[p] += 1;
	}
	else
	{
		int mid = (cl + cr) / 2;
		mark[2 * p] += mark[p], mark[2 * p + 1] += mark[p];
		if(mark[p] % 2)
		{tree[2 * p] = (mid - cl + 1) - tree[2 * p], tree[2 * p + 1] = (cr - mid) - tree[2 * p + 1];}
		mark[p] = 0;
		update(l, r, 2 * p, cl, mid);
		update(l, r, 2 * p + 1, mid + 1, cr);
		tree[p] = tree[2 * p] + tree[2 * p + 1];
	}
}
int query(int l, int r, int p, int cl, int cr)
{
	if(cl > r || cr < l)
		return 0;
	if(cl >= l && cr <= r)
		return tree[p];
	else
	{
		int mid = (cl + cr) / 2;
		mark[2 * p] += mark[p], mark[2 * p + 1] += mark[p];
		if(mark[p] % 2)
		{tree[2 * p] = (mid - cl + 1) - tree[2 * p], tree[2 * p + 1] = (cr - mid) - tree[2 * p + 1];}
		mark[p] = 0;
		return query(l, r, 2 * p, cl, mid) + query(l, r, p * 2 + 1, mid + 1, cr);
	}
}

我在算法书上看到:因为C艹的流输入的效率相对较慢,所以在题目有大量输入的时候,不建议用这个

所以我换成了C风格的输入输出

你可能感兴趣的:(算法)