这是一个代码简单的线段树,但其实不是很容易想到这种思路。
线段树要维护两个东西,一个suml(起点),sumr(终点);
插入的时候只需要在起点和终点sum++(区间维护,实际是点修改),如图:
查询x ~ y区间的时候需要用1~ y点的suml - 1 ~ x点的sumr;
为什么这样查询呢?大家仔细想想,用笔画画,这是个区间覆盖问题,大家一定要想通,结合插入来想想。(这里就不详细讲了,结合图片看看)。
#include
#include
#include
#include
#define rs id<<1|1
#define ls id<<1
using namespace std;
const int N=100000+10;
struct node
{
int left,right,sumr,suml;
}tree[N*4];
int n,m;
void build(int id,int l,int r)
{
tree[id].left=l,tree[id].right=r;
if(l==r)return;
int mid=(l+r)>>1;
build(ls,l,mid),build(rs,mid+1,r);
}
void update(int id,int x)//修改起点
{
if(tree[id].left==tree[id].right)
{
tree[id].suml++;return;
}
if(x>tree[ls].right)update(rs,x);
else update(ls,x);
tree[id].suml=tree[ls].suml+tree[rs].suml;
}
void update2(int id,int x)//修改终点
{
if(tree[id].left==tree[id].right)
{
tree[id].sumr++;return;
}
if(x>tree[ls].right)update2(rs,x);
else update2(ls,x);
tree[id].sumr=tree[ls].sumr+tree[rs].sumr;
}
int query(int id,int l,int r)//查询起点
{
if(r<tree[id].left || tree[id].right<l)return 0;
if(l<=tree[id].left&&tree[id].right<=r)return tree[id].suml;
return query(ls,l,r)+query(rs,l,r);
}
int query2(int id,int l,int r)//查询终点
{
if(tree[id].left>r||tree[id].right<l)return 0;
if(tree[id].left>=l&&tree[id].right<=r)return tree[id].sumr;
return query2(ls,l,r)+query2(rs,l,r);
}
int main()
{
scanf("%d%d",&n,&m);
build(1,1,n);//建树
for(int i=1;i<=m;i++)
{
int x,y,z;
scanf("%d%d%d",&x,&y,&z);
if(x==1)
{
update(1,y);update2(1,z);
}
if(x==2)
{
int s=query(1,1,z);
int t=query2(1,1,y-1);
printf("%d\n",s-t);//终点的sum-起点的sum
}
}
}