校门外的树
【题目分析】题目描述的是一种区间修改,看起来好像要用线段树。但是对于这种区间内部没有差别并且查询的是区间内的类别的问题,是可以转化为树状数组进行的。毕竟树状数组更加简单。
我们的关注点应该放在区间的端点处,然后通过统计端点得到答案。
我们不妨用数组a1保存左端点的个数,用数组a2保存右端点的个数(从开始到x)假如查询的是区间[l,r],那么a1[r]是区间[1,r]的种类数,a2[l-1]是区间[1,r]中不包含在[l,r]的种类数,答案就是a1[r]-a1[l-1]
代码:
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
int n,m,k,l,r;
const int MAXN=50005;
int a1[MAXN],a2[MAXN];
int lowbit(int x)
{
return x&(-x);
}
void update1(int x,int y)
{
while(x<=n)
{
a1[x]+=y;
x+=lowbit(x);
}
}
void update2(int x,int y)
{
while(x<=n)
{
a2[x]+=y;
x+=lowbit(x);
}
}
int ask1(int x)
{
int ret=0;
while(x)
{
ret+=a1[x];
x-=lowbit(x);
}
return ret;
}
int ask2(int x)
{
int ret=0;
while(x)
{
ret+=a2[x];
x-=lowbit(x);
}
return ret;
}
int main()
{
scanf("%d%d",&n,&m);
memset(a1,0,sizeof(a1));
memset(a2,0,sizeof(a2));
for(int i=0;i<m;i++)
{
scanf("%d%d%d",&k,&l,&r);
if(k==1)
{
update1(l,1);
update2(r,1);
}
else if(k==2)
{
printf("%d\n",ask1(r)-ask2(l-1));
}
}
return 0;
}