题意:
一个空的坐标系,有④种操作:①1 x y c表示在(x, y)点染上颜色c;②2 X y1 y2表示查询在(1, y1)到(X, y2)范围内有多少种不同的颜色:
③0表示清屏;④3表示程序退出(0<=x, y<=1000000, 0<=c<=50)
思路:开五十个线段树(一种颜色一个),以y为下表,保存min x,(因为查询x固定1---X)然后暴力查询50个就好了
但是显然碰到了一个问题,1e6 开50个线段树显然不现实。。所以需要空间优化一下。。。这里我们考虑动态来开辟线段树,有效的节点进行分配,无效则不分配。。。提问,这样空间为什么是合理的呢?其实因为一个add 最多开logn个节点,单组只有1.5e5次查询,显然,最多也就只开了qlogn个。那么这样空间复杂度就是合理的了。。具体动态开辟的实现也非常简单,类比trie,见代码。
代码:
#include<bits/stdc++.h>
using namespace std;
#define MEM(x,y) memset(x,y,sizeof(x));
const int maxn=3e6+10;
int root[55];
int L[maxn],R[maxn],tot,sum[maxn];
void update(int &rt,int idx,int val,int l,int r){
if(rt==-1) rt=tot++;
sum[rt]=min(val,sum[rt]);
if(l==r) return;
int mid=(l+r)/2;
if(idx<=mid) update(L[rt],idx,val,l,mid);
else update(R[rt],idx,val,mid+1,r);
return;
}
int query(int rt,int l,int r,int ll,int rr){
int ret=1e9;
if(rt==-1) return ret;
if(ll==l&&rr==r) return sum[rt];
int mid=(ll+rr)/2;
if(r<=mid) ret=query(L[rt],l,r,ll,mid);
else if(l>mid) ret=query(R[rt],l,r,mid+1,rr);
else ret=min(query(L[rt],l,mid,ll,mid),query(R[rt],mid+1,r,mid+1,rr));
return ret;
}
int main(){
int t,n,op,x,y,y1,y2,c,ret;
while(scanf("%d",&op)){
if(op==0){
MEM(L,-1);MEM(R,-1);
for(int i=0;i<maxn;++i) sum[i]=1e9;
tot=52;
}
else if(op==1){
scanf("%d%d%d",&x,&y,&c);
update(c,y,x,1,1e6);
}
else if(op==2){
scanf("%d%d%d",&x,&y1,&y2);
ret=0;
for(int i=0;i<=50;++i)
ret+=(query(i,y1,y2,1,1e6)<=x);
printf("%d
",ret);
}
else if(op==3) break;
}
}