链接:点击打开链接
题意:有三种操作,分别为:
0 清除矩阵中所有颜色
1 x y c 在(x,y)点涂上c颜色
2 x y1 y2 询问左上角为(1,y1),右上角为(x,y2)的矩阵中含有的颜色种数
代码:
#include <stack>
#include <string>
#include <vector>
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <iostream>
#include <algorithm>
using namespace std;
const int siz=1000005;
int id=0;
int rt[105],ll[siz],rr[siz],val[siz];
void build(int &s,int p,int L,int R,int x){
if(s==0){ //主要就是动态开点,需要时再建立节点
s=(++id); //并不会建一颗完整的线段树
val[s]=x; //剩下的跟静态建线段树是一样的
}
if(val[s]>x)
val[s]=x;
if(L==R)
return;
int m=(L+R)>>1;
if(p<=m)
build(ll[s],p,L,m,x);
else
build(rr[s],p,m+1,R,x);
}
void query(int p,int L,int R,int l,int r,int x,int &pos){
if(l<=L&&R<=r){ //查询时最好也不要遍历整颗树
if(val[p]<=x) //已经小于就不再继续遍历
pos=1;
return;
}
if(pos)
return;
int m=(L+R)>>1;
if(l<=m&&ll[p]!=0)
query(ll[p],L,m,l,r,x,pos);
if(r>m&&rr[p]!=0)
query(rr[p],m+1,R,l,r,x,pos); //整体思路就是建50颗线段树
} //按y轴建树,单点更新,求区间最小的x值
int main(){ //rt[i]表示i颜色线段树的根节点
int i,c,x,y1,y2,op,ans,pos; //ll[i]表示编号i节点的左儿子
memset(rt,0,sizeof(rt)); //rr[i]表示编号i节点的右儿子
memset(ll,0,sizeof(ll));
memset(rr,0,sizeof(rr));
while(scanf("%d",&op)&&op!=3){
if(op==0){
for(i=0;i<=50;i++)
rt[i]=0;
for(i=0;i<=id;i++)
ll[i]=rr[i]=0;
id=0;
}
else if(op==1){
scanf("%d%d%d",&x,&y1,&c);
build(rt[c],y1,1,1000000,x);
}
else if(op==2){
scanf("%d%d%d",&x,&y1,&y2);
ans=0;
for(i=0;i<=50;i++){
pos=0;
query(rt[i],1,1000000,y1,y2,x,pos);
if(pos==1)
ans++;
}
printf("%d\n",ans);
}
}
return 0;
}