CSU - 2170 千万别用树套树

本文介绍了一种使用线段树处理线段集合的插入和查询操作的方法。针对给定的操作序列,包括线段的插入和特定条件下的线段数量查询,通过构建线段树并更新节点状态,实现高效查询满足条件的线段数量。适用于数据结构和算法领域的学习和研究。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

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<bits/stdc++.h>
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) return 0; 
	if(l>=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<rr) ans+=getSum(mid+1,r,n<<1|1,ll,rr,t);
	return ans;
}
int main()
{
	while(~scanf("%d %d",&n,&m))
	{
		memset(ll,0,sizeof ll);
		memset(lr,0,sizeof lr);
		int cnt=0;
		while(m--)
		{
			int a,b,c;
			scanf("%d %d %d",&a,&b,&c);
			if(a==1)
			{
				cnt++;
				updata(1,n,1,b,ll);// ll记录线段开始端点 
				updata(1,n,1,c,lr);// lr记录线段结束端点 
			}
			else
			{
				//对于每次查询l-r,用cnt减去 开始端点比l大的线段
				// 用cnt减去结束端点比r小的线段就是答案了 
				printf("%d\n",(cnt-getSum(1,n,1,b+1,n,ll)-getSum(1,n,1,1,c-1,lr)));	
			}
		}
	}
	
}

 

 

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值