题目:http://acm.hdu.edu.cn/showproblem.php?pid=6183
题意:让你在一个棋盘上涂色,有4种操作
0:将棋盘清空
1:在(x,y)点涂上c的颜色
2:求(1,y1)到(x,y2)上颜色的种类数目
3:退出
因为在同一位置的颜色不会相互覆盖,所以考虑建立51棵线段树来维护各种颜色
之后发现求区间时 有一个x一定为1
那么如果按y坐标建立线段树,就只需要维护x的最小值就能够判断是否有颜色
如果区间内最小的x位置都比查询的区间的x大,那一定没有,否则一定有
因为51棵线段树的空间太大而修改次数不多,所以需要动态开点
#include<iostream> #include<cstdio> #include<cstring> #include<string> #include<cmath> #include<algorithm> #include<vector> #include<queue> #include<stack> #include<map> #include<set> using namespace std; const int N=1e6+5; int tree[55],ls[N<<2],rs[N<<2],minn[N<<2],cnt; void add(int &i,int l,int r,int k,int val) { if (i==0) { i=++cnt; minn[i]=val; } else minn[i]=min(minn[i],val); if (l==r) return; int mid=(l+r)>>1; if (k>mid) add(rs[i],mid+1,r,k,val); else add(ls[i],l,mid,k,val); } int flag; void query(int i,int l,int r,int L,int R,int x) { if (flag||i==0) return; if (L<=l&&r<=R) { if (minn[i]<=x) flag=1; return; } int mid=(l+r)>>1; if (L<=mid) query(ls[i],l,mid,L,R,x); if (R>mid) query(rs[i],mid+1,r,L,R,x); } int main() { while(1) { int opt; scanf("%d",&opt); int x,y,z; int ans; switch (opt) { case 0: memset(tree,0,sizeof(tree)); memset(ls,0,sizeof(ls)); memset(rs,0,sizeof(rs)); cnt=0; break; case 1: scanf("%d%d%d",&x,&y,&z); add(tree[z],1,N-5,y,x); break; case 2: scanf("%d%d%d",&x,&y,&z); if (y>z) swap(y,z); ans=0; for(int i=0;i<=50;i++) { flag=0; query(tree[i],1,N-5,y,z,x); ans+=flag; } printf("%d ",ans); break; case 3: return 0; } } return 0; }