B - Color itHDU - 6183
题目大意:有三种操作,0是清空所有点,1是给点(x,y)涂上颜色c,2是查询满足1<=a<=x,y1<=b<=y2的(a,b)点一共有几种不同的颜色
一开始做的时候直接就是开51个vector保存每个颜色相应的点,然后就是询问就是,暴力循环判断这个颜色存不存在一个满足条件的点,感觉最差情况下应该会超时,不过却过了
1 #include<cstdio> 2 #include<vector> 3 using namespace std; 4 struct Node{ 5 int x,y; 6 Node(){} 7 Node(int x,int y):x(x),y(y){} 8 }; 9 vector<Node> c[58]; 10 int main() 11 { 12 int op,x,y,y1,cc; 13 while(scanf("%d",&op)&&op!=3) 14 { 15 if(op==0) 16 { 17 for(int i=0;i<=50;i++) 18 c[i].clear(); 19 } 20 else if(op==1) 21 { 22 scanf("%d%d%d",&x,&y,&cc); 23 c[cc].push_back(Node(x,y)); 24 } 25 else 26 { 27 scanf("%d%d%d",&x,&y,&y1); 28 int ans=0; 29 for(int i=0;i<=50;i++) 30 { 31 for(int j=0;j<c[i].size();j++) 32 if(c[i][j].x<=x&&c[i][j].y>=y&&c[i][j].y<=y1) 33 { 34 ans++; 35 break; 36 } 37 } 38 printf("%d\n",ans); 39 } 40 } 41 return 0; 42 }
然后看网上有是线段树动态开点的做法,但实际上并不比上面暴力的写法快,反而慢上几十ms,不过可以当做一个算法扩展来联系。
首先1操作肯定就是单点更新了,而2操作上已经限定了x的左边为1,所以我们以y轴来建线段树维护个区间内x的最小值,那么2操作就是区间查询了。但我们知道正常静态的线段树需要4*SIZE的节点空间来保存信息的,在这里又需要51颗线段树,也就是51*4*1000000的空间来保存节点信息,不知道你们电脑能不能开那么大的数组,反正我的电脑和OJ的虚拟机是不行的。但其实最多150000个1操作和2操作,并不需要那么大的空间。所以这时候需要用到线段树的动态开点了。
静态的线段树,每个编号为x的节点,它的左孩子编号就为2*x,右孩子编号就为2*x+1,然后这个节点x,我们是保存它的区间L,R和其他一系列信息。而动态开点的话,对于编号为x的节点,它的左右孩子的编号就不一定是2*x和2*x+1的关系了,所以我们要保存下的是它的左右孩子的编号已经一系列相关的信息,然后对于每个节点就是当需要到它时再开辟它。其他操作就和静态的线段树差不多。
1 #include<cstdio> 2 #include<algorithm> 3 using namespace std; 4 const int N=1001108; 5 struct Tree{ 6 int lson,rson,minx; 7 }T[N]; 8 int tn,flag,root[52]; 9 //root就保存这个颜色对于的那棵线段树的根节点编号 10 void init() 11 { 12 tn=1; 13 for(int i=0;i<=50;i++) 14 root[i]=0; 15 } 16 void updata(int &id,int L,int R,int y,int x)//在这里用L,R来表示节点id的区间 17 { 18 if(!id) 19 {//需要到这个节点了,开辟这个节点 20 id=tn++; 21 T[id].minx=N; 22 T[id].lson=T[id].rson=0;//它的子节点还未用得上 23 } 24 T[id].minx=min(T[id].minx,x);//更新最小的x值 25 //下面就是线段树的单点修改 26 if(L==R) 27 return ; 28 int mid=(L+R)>>1; 29 if(y<=mid) 30 updata(T[id].lson,L,mid,y,x); 31 else 32 updata(T[id].rson,mid+1,R,y,x); 33 } 34 void query(int id,int L,int R,int l,int r,int x) 35 { 36 if(flag||!id)//如果已经有点满足条件,或者这个节点没开辟就返回 37 return ; 38 if(l<=L&&r>=R) 39 { 40 if(T[id].minx<=x) 41 flag=1;//在y1和y2范围内有个x满足条件 42 return ; 43 } 44 int mid=(L+R)>>1; 45 if(l<=mid) 46 query(T[id].lson,L,mid,l,r,x); 47 if(r>mid) 48 query(T[id].rson,mid+1,R,l,r,x); 49 } 50 int main() 51 { 52 int op,x,y,y2,c; 53 init(); 54 while(~scanf("%d",&op)&&op!=3) 55 { 56 if(op==0) 57 init(); 58 else if(op==1) 59 { 60 scanf("%d%d%d",&x,&y,&c); 61 updata(root[c],1,1000000,y,x); 62 } 63 else 64 { 65 scanf("%d%d%d",&x,&y,&y2); 66 int ans=0; 67 for(int i=0;i<=50;i++) 68 { 69 flag=0; 70 query(root[i],1,1000000,y,y2,x); 71 ans+=flag; 72 } 73 printf("%d\n",ans); 74 } 75 } 76 return 0; 77 }
正解是cdq分治,待我学成归来,再更新。。。