更新,区间查询--首先想到的都会是线段树,根据每种颜色建树,cnum<=51,查询的横坐标是[1,x2],对于每个y找最近的点,再判断树内区间点数
是不是知道线段树但不会敲?小记表同感TT,网上的模板一大堆,可是记不牢,因为没理解透彻,所以写题的我又重新看起了线段树,看到很多博主都会转一位大佬的线段树文章,小记也转了!
我们先学一波线段树吧:
看完这个,大概有点了解吧,再看下一个
#include<cstdio>
#include<cstring>
#include<cmath>
using namespace std;
const int N=1e6+5;
int left[N],right[N],v[N];
int flag,fl,fr,x2,cnt;
int root[55];//51种颜色
void update(int &k,int l,int r,int a,int b){//更新
int mid;
if(k==0)
{
k=++cnt;
v[k]=b;
}
if(v[k]>b)
v[k]=b;
if(l==r)
return;
mid=(l+r)/2;
if(a<=mid)
update(left[k],l,mid,a,b);
else
update(right[k],mid+1,r,a,b);
}
void query(int x,int l,int r){//查询
int mid;
if(flag||x==0)
return;
if(l>=fl&&r<=fr){
if(v[x]<=x2)
flag=1;
return;
}
mid=(l+r)/2;
if(fl<=mid)
query(left[x],l,mid);
if(fr>=mid+1)
query(right[x],mid+1,r);
}
int main(){
int i,ans,x,y,d,c;
while(1){
scanf("%d",&d);
if(d==3)
break;
else if(d==0){//恢复初始化
for(i=0;i<=cnt;i++)
left[i]=right[i]=0;
memset(root,0,sizeof(root));
cnt=0;
}
else if(d==1){//添加更新
scanf("%d%d%d",&x,&y,&c);
update(root[c],1,1000000,y,x);
}
else if(d==2){//查询范围内颜色个数
scanf("%d%d%d",&x2,&fl,&fr);//x1=1
ans=0;
for(i=0;i<=50;i++){
flag=0;
query(root[i],1,1000000);
ans+=flag;
}
printf("%d\n",ans);
}
}
return 0;
}