SSL2647 线段树练习题4【线段树】

SSL2647 线段树练习题4【线段树】_第1张图片

分析:

对于以后越来越复杂的线段树题,
先行构造一棵线段树,将左右区间放进去是个很好的选择。
这样后面的插入统计将会变得比较简单简便。

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;
}

图黄了~~

你可能感兴趣的:(题解,线段树)