小L的线段树
题号:NC311984
时间限制:C/C++/Rust/Pascal 2秒,其他语言4秒
空间限制:C/C++/Rust/Pascal 256 M,其他语言512 M
64bit IO Format: %lld

题目描述

\hspace{15pt}小L的科研毫无进展,于是他种了一棵线段树。
\hspace{15pt}在接下来 n 天里,每天会发生以下两类事件之一:(除叶子节点外的)树上某节点的信息被毁坏,或查询某个区间在该线段树上的代价。

\hspace{15pt}线段树的定义:将线段树视为一棵二叉树,每个节点对应一个闭区间 [l, r]
\hspace{23pt}\bullet\,l = r,则该节点为叶节点。
\hspace{23pt}\bullet\,l < r,令 mid = \lfloor (l + r) / 2 \rfloor。该节点的左子节点对应区间 [l, mid],右子节点对应区间 [mid + 1, r]
\hspace{15pt}根节点对应区间 [1, n]

\hspace{15pt}受损与信息获取:若某节点被毁坏,其信息可通过访问其左右两个子节点得到(即查询时遇到该节点则必须递归到子节点,该节点本身不提供信息)。

\hspace{15pt}查询代价:给定区间 [x, y],从根节点开始进行区间查询,过程如下:
\hspace{23pt}\bullet\,[l,r][x,y] 完全包含:
\hspace{38pt}\circ\,若该节点未被毁坏:计 1 次「有效访问」,并停止递归(该分支结束);
\hspace{38pt}\circ\,若该节点已被毁坏:不计数,直接对与 [x,y] 有交的子节点按上述规则递归访问。
\hspace{23pt}\bullet\,[l,r] 未被 [x,y] 完全包含:
\hspace{38pt}\circ\,若该节点未被毁坏:计 1 次「有效访问」;然后若左子节点对应区间与 [x, y] 有交则访问左子节点,若右子节点对应区间与 [x, y] 有交则访问右子节点;
\hspace{38pt}\circ\,若该节点已被毁坏:不计数,直接对与 [x, y] 有交的子节点按上述规则递归访问。

\hspace{15pt}定义 \text{cost}(x, y) 为完成对 [x, y] 的查询时,被计数的「有效访问」节点个数(即访问到的、未被毁坏的节点个数)。
\hspace{15pt}对于每个查询事件,你需要回答:在当前已发生的毁坏状态下,查询给定区间 [l, r]\text{cost}(l, r)

【名词解释】
\hspace{15pt}二叉树:满足以下全部条件的树。
\hspace{23pt}\bullet\,二叉树可以是空集;若不为空,则由一个根节点以及两棵互不相交的、分别称为左子树和右子树的二叉树组成;
\hspace{23pt}\bullet\,每个节点要么没有父节点连接(此时该节点被称为根节点)、要么被 1 个父节点连接(此时该节点被称为父节点的子节点);
\hspace{23pt}\bullet\,每个节点连接的子节点数量要么为 0 (此时该节点被称为叶子节点),要么不超过 2,且此时每个子节点都有明确的“左”或“右”属性。

输入描述:

\hspace{15pt}第一行输入一个正整数 n\left(1 \le n \le 10^6\right),同时用于表示事件总数和线段树的根节点对应的区间长度。
\hspace{15pt}此后 n 行,第 i 行先输入一个整数 o_i \left(1 \le o_i \le 2\right),表示第 i 天发生的事件类型,随后在同一行:
\hspace{23pt}\bullet\,o_i = 1,输入两个整数 l_i, r_i \left(1 \le l_i \lt r_i \le n\right),表示毁坏了 [l_i, r_i] 区间所代表的节点,保证仅对应线段树上的一个节点,同一个节点可能被毁坏多次;
\hspace{23pt}\bullet\,o_i = 2,输入两个整数 l_i, r_i \left(1 \le l_i \le r_i \le n\right),表示想要获取 [l_i, r_i] 区间的信息。

输出描述:

\hspace{15pt}对于每一个 o_i = 2 的事件,新起一行输出一个整数,表示 \text{cost}(l_i, r_i) 的值。
示例1

输入

复制
4
2 1 4
1 1 4
2 1 4
2 1 2

输出

复制
1
2
1