题意:
维护一个数据结构,支持三种操作:
①在平面上(x,y)处添加一个颜色为c的点。
②询问平面上(1,y1)-(x,y2)范围内,有多少种不同颜色的点。
③清除平面上所有点。
颜色数量很少,对于每种颜色分别建立线段树,然后用线段树维护y坐标,对每个y坐标只存下来x坐标最小的点的x坐标,然后每次询问相当于问你[y1,y2]区间的最小值是否小于等于x。
卡常数,必须用动态开点线段树,并且在询问的时候进行剪枝(在区间内如果遇到了满足条件的子区间,直接返回true,不继续检查其他子区间了)。
#include<cstdio> #include<cstring> #include<algorithm> using namespace std; const int INF=2147483647; int root[55],lc[4000005],rc[4000005],v[4000005]; int tot; void newnode(int &rt){ rt=++tot; lc[rt]=rc[rt]=0; v[rt]=INF; } void update(int p,int x,int &rt,int l,int r){ if(!rt){ newnode(rt); } if(l==r){ v[rt]=min(v[rt],x); return; } int m=(l+r>>1); if(p<=m){ update(p,x,lc[rt],l,m); } else{ update(p,x,rc[rt],m+1,r); } v[rt]=min(v[lc[rt]],v[rc[rt]]); } bool query(int x,int ql,int qr,int rt,int l,int r) { if(!rt){ return 0; } if(ql<=l && r<=qr){ if(v[rt]<=x){ return 1; } return 0; } int m=(l+r>>1); if(ql<=m){ if(query(x,ql,qr,lc[rt],l,m)){ return 1; } } if(m<qr){ if(query(x,ql,qr,rc[rt],m+1,r)){ return 1; } } return 0; } int main() { // freopen("b.in","r",stdin); int op,x,y,z; v[0]=INF; while(1){ scanf("%d",&op); if(op==3){ break; } if(op==0){ memset(root,0,sizeof(root)); tot=0; } else if(op==1){ scanf("%d%d%d",&x,&y,&z); update(y,x,root[z],1,1000000); } else if(op==2){ scanf("%d%d%d",&x,&y,&z); int ans=0; for(int i=0;i<=50;++i){ ans+=query(x,y,z,root[i],1,1000000); } printf("%d ",ans); } } return 0; }