题目: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\n",ans);
break;
case 3:
return 0;
}
}
return 0;
}