【线段树】hdu6183 Color it

时间:2022-06-03 23:28:31

题意:

维护一个数据结构,支持三种操作:

①在平面上(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\n",ans);
		}
	}
    return 0;  
}