对于以后越来越复杂的线段树题,
先行构造一棵线段树,将左右区间放进去是个很好的选择。
这样后面的插入和统计将会变得比较简单简便。
void build(int x)
{
if(seg[x].r-seg[x].l>1) //当前节点不是叶子结点
{
int mid=(seg[x].l+seg[x].r)/2; //取中
seg[x*2].l=seg[x].l,seg[x*2].r=mid; //往左子树走
seg[x*2+1].l=mid,seg[x*2+1].r=seg[x].r; //往右子树走
build(x*2),build(x*2+1); //递归节点
}
}
值得注意的是,这道题统计的是 [ a , b ] [a,b] [a,b]区间的线段数目,、
所以我们要弄一个 c c c去统计每一个区间的线段数目,最后才容易累加线段树(递归或 w h i l e while while一次完成)
其他的操作就大同小异了(这道题甚至比线段树三还简单)
P s Ps Ps:结构体是个好东西
具体:
#include
#include
#include
#include
using namespace std;
int n,m,x,y,s,t;
struct node
{
int l,r;
int c;
}seg[4000010];
void build(int x)
{
if(seg[x].r-seg[x].l>1)
{
int mid=(seg[x].l+seg[x].r)/2;
seg[x*2].l=seg[x].l,seg[x*2].r=mid;
seg[x*2+1].l=mid,seg[x*2+1].r=seg[x].r;
build(x*2),build(x*2+1);
}
}
void insert(int x,int l,int r)
{
int mid=(seg[x].l+seg[x].r)/2;
if(seg[x].l==l&&seg[x].r==r) //当插入的线段完全覆盖某区间,就直接将那个区间的线段数目++
seg[x].c++;
else if(r<=mid)
insert(x*2,l,r);
else if(l>=mid)
insert(x*2+1,l,r);
else
insert(x*2,l,mid),insert(x*2+1,mid,r);
}
int ccount(int x,int l,int r)
{
int ans=seg[1].c; //从树根开始统计
while(seg[x].r-seg[x].l>1)
{
int mid=(seg[x].l+seg[x].r)/2;
if(seg[x].l==l&&seg[x].r==r)
break;
else if(r<=mid) //递归求线段总数
x*=2,ans+=seg[x].c;
else if(l>=mid)
x=x*2+1,ans+=seg[x].c;
}
return ans;
}
int main()
{
cin>>m>>n;
seg[1].l=1;
seg[1].r=m;
build(1);
for(int i=1; i<=n; i++)
{
scanf("%d%d",&x,&y);
insert(1,x,y);
}
cin>>s>>t;
cout<<ccount(1,s,t);
return 0;
}
图黄了~~