CSU - 2170 千万别用树套树

Description

Bobo 精通数据结构!他想维护一个线段的集合 S。初始时,S 为空。他会依次进行 q 次操作,操作有 2 种。

  • 类型 1:给出 l, r,向集合 S 中插入线段 [l, r].
  • 类型 2:给出 l, r,询问满足 [x, y]∈Sx ≤ l ≤ r ≤ y 的线段 [x, y] 数量。

帮 Bobo 求出每次询问的答案。

  • 1 ≤ n, q ≤ 105
  • ti ∈ {1, 2}
  • 1 ≤ li ≤ ri ≤ n
  • 对于 ti = 2 的操作,ri − li ≤ 2 成立。
  • 数据组数不超过 10.

Input

输入文件包含多组数据,请处理到文件结束。

每组数据的第一行包含 2 个整数 nq. 其中 n 表示操作中 r 的最大值。

接下来 q 行中的第 i 行包含 3 个整数 ti, li, ri,表示第 i 个操作属于类型 ti,对应的参数是 liri.

Output

对于每个类型 2 的询问,输出 1 个整数表示对应的数量。

Sample Input

1 2
1 1 1
2 1 1
4 4
1 1 4
2 2 3
1 1 4
2 2 3

Sample Output

1
1
2

这是一道可以用线段树写的题目,注意类型2的操作,类型 2:给出 l, r,询问满足 [x, y]∈Sx ≤ l ≤ r ≤ y 的线段 [x, y] 数量。

即给定的l,r一定要有完整的一条线段覆盖在上面才可以。

 

假设给定4个点,4种操作

操作1: 插入1-4线段。

操作2:插入3-4线段。

操作3:查询区间3-4。

操作4:查询区间2-3。

此时应该输出 2和1(第二次查询中只有一条线段覆盖了2-3)。

建树用两个数组记录开始和结束的点,用cnt记录插入操作的次数,对于每次查询如果l-r如果开始的数组比l+1大就用cnt-区间在l+1到n的线段,然后减去结束点在1到r-1的线段数就是答案了。

具体看代码理解

#include
using namespace std;
int n,m;
const int maxn=1e5+5;
int ll[maxn*4],lr[maxn*4];
void updata(int l,int r,int n,int x,int t[])
{
	if(l==r)
	{
		t[n]++;
		return ;
	}
	int mid=(l+r)>>1;
	if(mid>=x) updata(l,mid,n<<1,x,t);
	else updata(mid+1,r,n<<1|1,x,t);
	t[n]=t[n<<1]+t[n<<1|1];
}
int getSum(int l,int r,int n,int ll,int rr,int t[])
{
	if(l>rr||r=ll&&r<=rr) return t[n]; //区间内直接加上线段 数然后返回就可以了 
	int mid=(l+r)>>1;
	int ans=0;
	if(mid>=ll) ans+=getSum(l,mid,n<<1,ll,rr,t);
	if(mid

 

 

你可能感兴趣的:(CSU - 2170 千万别用树套树)