题意:有下面四个操作
0:情况所有数据
1 x y c:给点(x,y)添加一个颜色c
2 x y1 y2:问所有满足1<=a<=x&&y1<=b<=y2条件的点(a,b)共有多少中颜色
3:退出程序
分析:首先要仔细读题,题目说1 x y c是给(x,y)这个点加一个颜色c,也就是说一个点可以有多种颜色。
最多有51种颜色,那我们就根据每种颜色来建线段树,共51棵线段树,每颗线段树结点保存的值是当前区间的最小x(因为我们的x选择范围在[1,x]
(有点像二维线段树…
参考代码:
/*线段树*/ #include<cstdio> #include<cmath> #include<cstring> #include<algorithm> #include<iostream> using namespace std; #define mem(a,b) memset(a,b,sizeof(a)) const int maxn = 1e6+10; //线段树 int tot;//结点数 int s[55];//根据颜色来建线段树,最多51种颜色,所有最多也只会建50棵线段树 int lson[maxn],rson[maxn],v[maxn];//左右儿子,每个结点对应范围内的最小x值 int flag; void Update( int &k, int l, int r, int y, int x) { if( !k)//以前没出现过这种颜色 { k = ++tot; lson[k] = rson[k] = 0; v[k] = x; } v[k] = min(v[k],x); if( l == r) return; int mid = (l+r)>>1; if( y <= mid) Update(lson[k],l,mid,y,x); else Update(rson[k],mid+1,r,y,x); } void Query( int k, int l, int r, int L, int R, int x) { if( flag || !k) return; if( L <= l && R >= r) { if( v[k] <= x)//[1,x] flag = 1; return; } int mid = (l+r)>>1; if( R <= mid) Query(lson[k],l,mid,L,R,x); else if( L > mid) Query(rson[k],mid+1,r,L,R,x); else { Query(lson[k],l,mid,L,mid,x); Query(rson[k],mid+1,r,mid+1,R,x); } } int main() { int op; while( ~scanf("%d",&op)) { if( op == 0) { tot = 0; mem(s,0); } else if( op == 1) { int x,y,c; scanf("%d%d%d",&x,&y,&c); Update(s[c],1,1000000,y,x); } else if( op == 2) { int x,y1,y2; scanf("%d%d%d",&x,&y1,&y2); int ans = 0; for( int i = 0; i <= 51; i++) { flag = 0; Query(s[i],1,1000000,y1,y2,x); if( flag) ans++; } printf("%d\n",ans); } else if( op == 3) break; } return 0; }