题目: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; }
hdu 5372 Segment Game(树状数组+离散化)
原文地址:http://blog.csdn.net/w20810/article/details/47442793