Description
在x轴上进行两种操作
0 a:表示插入线段[a,a+i],其中i是该操作的次数
1 a:表示删除第a次放置的线段(保证删除合法)
每次放完一个线段后,问被这个线段完全包含的线段数量
Input
多组用例,每组用例第一行一整数n表示操作次数,之后n行每行两个整数a和b表示一次操作,以文件尾结束输入(1<=n<=200000,sum(n)<=700000,|b|< 10^9)
Output
对于每组用例,在每次插入操作时输出被当前线段包含的线段数量
Sample Input
3
0 0
0 3
0 1
5
0 1
0 0
1 1
0 1
0 0
Sample Output
Case #1:
0
0
0
Case #2:
0
1
0
2
Solution
由于当前放置的线段[l,r]一定是x轴现有线段中最长的,所以被包含的线段满足必然是右端点不大于r且左端点不小于l的,那么我们用两个树状数组分别统计左端点小于l的线段数量cnt1以及右端点小于等于r的线段树良cnt2,则cnt2-cnt1即为答案,时间复杂度O(nlogn),注意区间端点过大需要离散化一下
Code
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;
#define maxn 222222
struct BIT
{
#define lowbit(x) (x&(-x))
int b[maxn];
void init()
{
memset(b,0,sizeof(b));
}
void add(int x,int v)
{
while(x<maxn)
{
b[x]+=v;
x+=lowbit(x);
}
}
int sum(int x)
{
int ans=0;
while(x)
{
ans+=b[x];
x-=lowbit(x);
}
return ans;
}
};
BIT L,R;
int n,res=1,q[maxn],a[maxn],b[maxn],pos[maxn],l[maxn],r[maxn],len,cnt1,cnt2;
int main()
{
while(~scanf("%d",&n))
{
L.init(),R.init();
len=1,cnt1=cnt2=0;
for(int i=1;i<=n;i++)
{
scanf("%d%d",&q[i],&l[i]);
if(!q[i])
{
r[i]=l[i]+len;
pos[len++]=i;
a[cnt1++]=l[i],b[cnt2++]=r[i];
}
}
sort(a,a+cnt1),sort(b,b+cnt2);
cnt1=unique(a,a+cnt1)-a;
cnt2=unique(b,b+cnt2)-b;
printf("Case #%d:\n",res++);
for(int i=1;i<=n;i++)
{
if(q[i])
{
int temp=pos[l[i]];
int tl=lower_bound(a,a+cnt1,l[temp])-a+1;
int tr=lower_bound(b,b+cnt2,r[temp])-b+1;
L.add(tl,-1),R.add(tr,-1);
}
else
{
int tl=lower_bound(a,a+cnt1,l[i])-a+1;
int tr=lower_bound(b,b+cnt2,r[i])-b+1;
int ans=R.sum(tr)-L.sum(tl-1);
L.add(tl,1),R.add(tr,1);
printf("%d\n",ans);
}
}
}
return 0;
}