题目梗概
有两种操作:
一种是插入一段区间,并删除与这段区间相交的区间,返回删除区间的个数。
另一种是返回目前的区间数。
解题思路
有一个非常重要的特性是在任何时候区间的末端随区间的始端递增而递增。
于是考虑树状数组维护始端个数的前缀和,维护这个就可以二分查找小于等于某个点最近的始端。
知道始端的位置后,我们可以得到相应的末端,如果形成相交就删去这个区间(其实就是删去始端)。
因为始末端的单调性,当查找出的区间不形成相交就可以停止了。
因为每个区间最多被删去一次,所以效率为 O(N∗log2N)
#include<cstdio>
using namespace std;
const int N=100000;
inline int _read(){
int num=0;char ch=getchar();
while(ch<'0'||ch>'9') ch=getchar();
while(ch>='0'&&ch<='9') num=num*10+ch-48,ch=getchar();
return num;
}
int n,a[N+5],r[N+5];
int lowbit(int x){return x&(-x);}
void add(int x,int y){for (;x<=N;x+=lowbit(x)) a[x]+=y;}
int ask(int x){int num=0;for (;x;x-=lowbit(x)) num+=a[x];return num;}
int main(){
freopen("exam.in","r",stdin);
freopen("exam.out","w",stdout);
n=_read();
for (int i=1;i<=n;i++){
char ch=getchar();
while(ch!='A'&&ch!='B') ch=getchar();
if (ch=='B') printf("%d\n",ask(N));else{
int x=_read(),y=_read(),tot=0;
while(1){
int L=1,R=y,mid,w=ask(y),h;
if (!w) break;
while(L<=R){
int mid=L+(R-L>>1);
if (ask(mid)>=w) h=mid,R=mid-1;else L=mid+1;
}
if (r[h]>=x) add(h,-1),tot++;else break;
}
add(x,1);r[x]=y;
printf("%d\n",tot);
}
}
return 0;
}