首页 > 其他分享 >开关(线段树区间异或板子)

开关(线段树区间异或板子)

时间:2022-08-17 19:15:22浏览次数:57  
标签:le la int sum long 板子 异或 区间 线段

[TJOI2009] 开关

题目描述

现有 \(n\) 盏灯排成一排,从左到右依次编号为:\(1\),\(2\),……,\(n\)。然后依次执行 \(m\) 项操作。

操作分为两种:

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

灯在初始时都是关着的。

输入格式

第一行有两个整数 \(n\) 和 \(m\),分别表示灯的数目和操作的数目。

接下来有 \(m\) 行,每行有三个整数,依次为:\(c\)、\(a\)、\(b\)。其中 \(c\) 表示操作的种类。

  • 当 \(c\) 的值为 \(0\) 时,表示是第一种操作。
  • 当 \(c\) 的值为 \(1\) 时,表示是第二种操作。

\(a\) 和 \(b\) 则分别表示了操作区间的左右边界。

输出格式

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

样例 #1

样例输入 #1

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

样例输出 #1

1
2

提示

数据规模与约定

对于全部的测试点,保证 \(2\le n\le 10^5\),\(1\le m\le 10^5\),\(1\le a,b\le n\),\(c\in\{0,1\}\)。

思路:

用懒标标记一下,如果为1,下传时子区间懒标取反, \(sum\) = 区间长度- \(sum\)即可

代码:

#include <bits/stdc++.h>
#define maxn 400005
#define ll long long
#define ull unsigned long long
using namespace std;
int n, m;
int sum[maxn], la[maxn];
void push_up (int i) {
	sum[i] = sum[i * 2] + sum[i * 2 + 1];
}
void push_down (int l, int r, int i) {
	int mid = (r + l) >> 1;
	if (la[i]) {
		la[i * 2] ^= 1, la[i * 2 + 1] ^= 1;
		sum[i * 2] = mid - l + 1 - sum[i * 2];
		sum[i * 2 + 1] = r - mid - sum[i * 2 + 1];
		la[i] = 0;
	}
}
void open(int l, int r, int s, int t, int i) {
	int mid = (s + t) >> 1;
	if (l <= s && t <= r) {
		sum[i] = t - s + 1 - sum[i];
		la[i] = !la[i];
		return;
	}
	push_down(s, t, i);
	if (l <= mid) open(l, r, s, mid, i * 2);
	if (mid + 1 <= r) open(l, r, mid + 1, t, i * 2 + 1);
	push_up(i);
}
int query(int l, int r, int s, int t, int i) {
	int mid = (s + t) >> 1;
	int ans = 0;
	if (l <= s && t <= r) return sum[i];
	push_down(s, t, i);
	if (l <= mid) ans += query(l, r, s, mid, i * 2);
	if (mid + 1 <= r) ans += query(l, r, mid + 1, t, i * 2 + 1);
	return ans;
}
int main () {
	cin >> n >> m;
	while (m--) {
		int op, x, y;
		cin >> op >> x >> y;
		if (op) cout << query(x, y, 1, n, 1) << endl;
		else open(x, y, 1, n, 1);
	}
	return 0;
}

标签:le,la,int,sum,long,板子,异或,区间,线段
From: https://www.cnblogs.com/misasteria/p/16596452.html

相关文章

  • 172 树套树 线段树套平衡树
    视频链接:LuoguP3380【模板】二逼平衡树(树套树)//需要开O2#include<iostream>#include<algorithm>usingnamespacestd;#defineN2000010#defineINF21474836......
  • swap(a, b)异或骚操作方法
    众所周知,平日里我们如果要交换两个变量的时候,通常都是voidswap(inta,intb){inttemp=a;a=b;b=temp;}通过创建temp变量,保存其中一个的值,再交......
  • 线段树模板【带懒标记】
    #include<bits/stdc++.h>usingnamespacestd;typedeflonglongll;constintN=1e5+10;inta[N];structnode{  intl,r;  lladd,sum;  node(){  ......
  • YbtOJ 「数据结构」第4章 线段树
    不想dp了怎么办?开个新坑吧。例题1.求区间和树状数组不香吗,28行解决(bushi所以懒得打线段树了。code#include<bits/stdc++.h>#defineintlonglongusingnamespac......
  • 子数组异或和(前缀和、哈希)
    题意给定一个长度为\(n\)的整数数组\(a_1,a_2,\dots,a_n\)。请你统计一共有多少个数组\(a\)的非空连续子数组能够同时满足以下所有条件:该连续子数组的长度为偶数。......
  • 洛谷 P6242 【模板】线段树 3 吉司机线段树 区间取最小值 维护历史最大值和区间和
    题目背景本题是线段树维护区间最值操作与区间历史最值的模板。题目描述给出一个长度为 nn 的数列 AA,同时定义一个辅助数组 BB,BB 开始与 AA 完全相同。接下来......
  • 线段树----区间问题的神
    《标准线段树》  普通的线段树,其区间一般都是一个序列的数的个数,但还是要根据不同题目来判断注意:tr[]空间是N*4,N为最大范围《单点修改,区间查询》原题:https://www.......
  • 动态开点线段树
    动态开点线段树为了准备google的面试刷题的时候发现这个知识点其实我一直不太熟悉,所以专门写一篇blog准备一下。我们将从以下几个方面去讲解:目录动态开点线段树什么是......
  • 线段树
    线段树学习笔记1.线段树简介线段树,是一种二叉搜索树,其每一个节点表示了一段区间。线段树支持的操作有:区间求和或最大/最小值,时间复杂度\(O(logN)\)(p.s.后面代......
  • luoguP3521 [POI2011]ROT-Tree Rotations【线段树】
    你要写热,就不能只写热。要写酷暑,写骄阳,写他人耳闻便生恐的炙烤和炎灼。要写白日出门一刻便肤色黝黑,背心透彻。写求雨心切,写出行伞遮。写夜晚不停的风扇和蝉聒。写鸡......