问题描述
Bobo 精通数据结构!他想维护一个线段的集合 S。初始时,S 为空。他会依次进行 q 次操作,操作有 2 种。
类型 1:给出 l, r,向集合 S 中插入线段 [l, r].
类型 2:给出 l, r,询问满足 [x, y]∈S 且 x ≤ 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 个整数 n 和 q. 其中 n 表示操作中 r 的最大值。
接下来 q 行中的第 i 行包含 3 个整数 ti, li, ri,表示第 i 个操作属于类型 ti,对应的参数是 li 和 ri.
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
思路:
开两棵权值线段树
一棵维护区间左端点L的数量
一棵维护区间右端点R的数量
查询的时候,答案就是:
总区间数量 - 左端点大于L的区间数量 - 右端点小于R的区间数量
code:
#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<cmath>
using namespace std;
const int maxm=1e5+5;
struct Tree{
int a[maxm<<2];
void init(){//初始化
memset(a,0,sizeof a);
}
void update(int x,int l,int r,int node){//单点增加
a[node]++;
if(l==r)return ;
int mid=(l+r)/2;
if(x<=mid)update(x,l,mid,node*2);
else update(x,mid+1,r,node*2+1);
}
int ask(int st,int ed,int l,int r,int node){//区间求和
if(a[node]==0)return 0;
if(st<=l&&ed>=r)return a[node];
int mid=(l+r)/2;
int ans=0;
if(st<=mid)ans+=ask(st,ed,l,mid,node*2);
if(ed>=mid+1)ans+=ask(st,ed,mid+1,r,node*2+1);
return ans;
}
}t1,t2;
int n,q;
signed main(){
while(scanf("%d%d",&n,&q)!=EOF){
t1.init();//reset
t2.init();
int cnt=0;//总区间个数
while(q--){
int d,x,y;
scanf("%d%d%d",&d,&x,&y);
if(d==1){//添加
cnt++;//区间个数加1
t1.update(x,1,n,1);
t2.update(y,1,n,1);
}else{//查询
int ans=cnt;
ans-=t1.ask(x+1,n,1,n,1);//减去左端点大于l的区间数量
ans-=t2.ask(1,y-1,1,n,1);//减去右端点小于r的区间数量
printf("%d\n",ans);
}
}
}
return 0;
}