题目:http://acm.hdu.edu.cn/showproblem.php?pid=5372
题意:有两种操作,输入a b,①a==0,插入第i条线段[b,b+i],输出[b,b+i]内有多少条完全包含于[b,b+i]的线段②a==1,删除插入的第b条线段。
分析:由于插入的线段长度是递增的,那么就不存在包含[b,b+i]的线段。那么完全包含于[b,b+i]的线段的数目=右端点小于等于b+i的线段的数目-左端点小于b的线段的数目。由于输入的数比较大,离散化一下就行了。
代码:
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
using namespace std;
const int maxn = 4e5+8;
int L[maxn],R[maxn],lowbit[maxn],x[maxn],y[maxn],f[maxn*2],Kind,ax[maxn],ay[maxn];
void getlowbit()
{
for(int i=1;i<maxn;i++)
lowbit[i]=i&-i;
}
void update(int a[],int x,int v)
{
for(int i=x;i<maxn;i+=lowbit[i])
a[i]+=v;
}
int query(int a[],int x)
{
int ret(0);
for(int i=x;i>0;i-=lowbit[i])
ret+=a[i];
return ret;
}
int Find(int x)
{
int down=0,up=Kind-1,mid;
while(down<=up)
{
mid=(down+up)>>1;
if(f[mid]>x)
up=mid-1;
else if(f[mid]<x)
down=mid+1;
else
return mid+2;
}
return 0;
}
int main()
{
getlowbit();
int ncase=1,q,a,b,i,j;
while(scanf("%d",&q)!=EOF)
{
int cnt=0,c=0,aq=0;
for(i=1;i<=q;i++)
{
scanf("%d%d",&x[i],&y[i]);
if(x[i]==0)
{
aq++;
ax[aq]=y[i];
ay[aq]=y[i]+aq;
f[cnt++]=y[i];
f[cnt++]=y[i]+aq;
}
}
sort(f,f+cnt);
Kind=unique(f,f+cnt)-f;
memset(L,0,sizeof(L));
memset(R,0,sizeof(R));
printf("Case #%d:\n",ncase++);
c=0;
for(i=1;i<=q;i++)
{
if(x[i]==0) //add
{
c++;
printf("%d\n",query(R,Find(y[i]+c))-query(L,Find(y[i])-1));
update(L,Find(y[i]),1);
update(R,Find(y[i]+c),1);
}
else
{
update(L,Find(ax[y[i]]),-1);
update(R,Find(ay[y[i]]),-1);
}
}
}
return 0;
}