【题目】
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;
}