【HDU 6183】Color it

【题目】

传送门

Problem Description

Do you like painting? Little D doesn’t like painting, especially messy color paintings. Now Little B is painting. To prevent him from drawing messy painting, Little D asks you to write a program to maintain following operations. The specific format of these operations is as follows.

0 : clear all the points.

1 x y c : add a point which color is c at point (x,y).

2 x y1 y2 : count how many different colors in the square (1,y1) and (x,y2). That is to say, if there is a point (a,b) colored c, that 1≤a≤x and y1≤b≤y2, then the color c should be counted.

3 : exit.

Input

The input contains many lines.

Each line contains a operation. It may be ‘0’, ‘1 x y c’ ( 1≤x,y≤ 1 0 6 10^6 106,0≤c≤50 ), ‘2 x y1 y2’ (1≤x,y1,y2≤ 1 0 6 10^6 106 ) or ‘3’.

x,y,c,y1,y2 are all integers.

Assume the last operation is 3 and it appears only once.

There are at most 150000 continuous operations of operation 1 and operation 2.

There are at most 10 operation 0.

Output

For each operation 2, output an integer means the answer .

Sample Input

0
1 1000000 1000000 50
1 1000000 999999 0
1 1000000 999999 0
1 1000000 1000000 49
2 1000000 1000000 1000000
2 1000000 1 1000000
0
1 1 1 1
2 1 1 2
1 1 2 2
2 1 1 2
1 2 2 2
2 1 1 2
1 2 1 3
2 2 1 2
2 10 1 2
2 10 2 2
0
1 1 1 1
2 1 1 1
1 1 2 1
2 1 1 2
1 2 2 1
2 1 1 2
1 2 1 1
2 2 1 2
2 10 1 2
2 10 2 2
3

Sample Output

2
3
1
2
2
3
3
1
1
1
1
1
1
1


【分析】

首先,对于操作 0 0 0,可以看成多组数据,直接手动清零就行,操作 3 3 3 是退出,也不说了

剩下的就是比较难的 2 , 3 2,3 2,3 操作了

观察数据范围发现, c c c 的取值范围很小,只有 [ 0 , 50 ] [0,50] [0,50],于是想到对于每一种颜色建一颗线段树,然后每次询问时我们对每种颜色都来查询一遍,如果有一个点满足要求,答案就加一

这个时候,又看到题目中有一个特殊的地方,就是左下角的横坐标始终为 1 1 1,也就是说,在同一种颜色,同一个纵坐标的情况下,横坐标小的肯定更优(因为如果横坐标大的满足条件,小的肯定也能满足)

所以,在建造线段树的时候,只需要维护每一个纵坐标下,横坐标的最小值就可以了

还有一个问题,就是如果直接暴力开 50 50 50 颗线段树,空间肯定承受不下(可以自己手推一下),这个时候就需要用动态开点,这样实际使用的空间只与修改次数有关了

这里吐个槽(自行忽略):为什么我的程序跑的非慢而我的同学们一个个快得飞起???


【代码】

#include<cstdio>
#include<cstring>
#include<algorithm>
#define C 55
#define N 1000005
#define Node 20000005
#define inf 0x3f3f3f3f
using namespace std;
int tot,root[C],lc[Node],rc[Node],Min[Node];
void init()
{
	tot=0;
	Min[0]=inf;
	lc[0]=rc[0]=0;
	memset(root,0,sizeof(root));
}
void insert(int &root,int l,int r,int x,int val)
{
	if(!root)  root=++tot,Min[root]=val,lc[root]=rc[root]=0;
	if(l==r)  {Min[root]=min(Min[root],val);return;}
	int mid=(l+r)>>1;
	if(x<=mid)  insert(lc[root],l,mid,x,val);
	else  insert(rc[root],mid+1,r,x,val);
	Min[root]=min(Min[lc[root]],Min[rc[root]]);
}
int query(int root,int l,int r,int x,int y)
{
	if(!root)  return inf;
	if(l>=x&&r<=y)  return Min[root];
	int mid=(l+r)>>1;
	if(y<=mid)  return query(lc[root],l,mid,x,y);
	if(x>mid)  return query(rc[root],mid+1,r,x,y);
	return min(query(lc[root],l,mid,x,y),query(rc[root],mid+1,r,x,y));
}
int main()
{
	int s,i,c,x,y;
	while(~scanf("%d",&s))
	{
		if(s==3)  break;
		else  if(s==0)  init();
		else
		{
			scanf("%d%d%d",&x,&y,&c);
			if(s==1)  insert(root[c],1,N,y,x);
			else
			{
				int ans=0;
				for(i=0;i<=50;++i)
				  if(query(root[i],1,N,y,c)<=x)
				    ans++;
				printf("%d\n",ans);
			}
		}
	}
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值