线段树 基础练习例子(一)

来源:互联网 发布:淘宝网上茶杯犬多少钱 编辑:程序博客网 时间:2024/06/06 03:58

题目大意:桌子上零散地放着若干个盒子,桌子的后方是一堵墙。如右图所示。现在从桌子的前方射来一束平行光, 把盒子的影子投射到了墙上。问影子的总宽度是多少?

这道题目是一个经典的模型。在这里,我们略去某些处理的步骤,直接分析重点问题,可以把题目抽象地描述如下:x轴上有若干条线段,求线段覆盖的总长度。

给线段树每个节点增加一个域cover。cover=1表示该结点所对应的区间被完全覆盖,cover=0表示该结点所对应的区间未被完全覆盖。

 

 


program:

#include<iostream>
using namespace std;
int sum;
int n,m; 
struct linetree
{
  int a,b;
  int cover;      
}d[2*(100-1)-1];
void make_tree(int p,int a,int b)
{  

   
    //if(a==b)return ;
    d[p].a=a;//因为判断返回的一层提早了一层,所以判断要在记录之后。
    d[p].b=b;
    d[p].cover=0;
    cout<<"ab "<<a<<' '<<b<<endl;
    cout<<"d[p].a d[p].b "<<d[p].a<<' '<<d[p].b<<endl;
    if(a+1==b)return ;//这个是线段树的特征,因为右孩子没有像mid+1这样操作,所以最终在叶子节点的右孩子是不会出现mid=b的。从而出现死循环
    int mid= (a+b)/2;
    cout<<"mid "<<mid<<endl;
    make_tree(p*2,a,mid);
    make_tree(p*2+1,mid,b);
   
    
        
}
void line_insert(int p,int a,int b)
{      
        int mid=(d[p].a+d[p].b)/2;
        if(d[p].cover==1)return;//如果已经完全覆盖就可以不用再管,因为又不是涂颜色,只是计算长度而已
        if(a==d[p].a&&b==d[p].b)
         {
          d[p].cover=1;//这个操作可以细化到每一个单位长度,所以也是最底层的操作
          return;                     
         }    
       
        else if(b<=mid)//如果插入的数据全部在左孩子,就直接在左孩子中找
            line_insert(p<<1,a,b);
        else if(a>=mid)
            line_insert(p<<1|1,a,b);//同上换右孩子
        else  //否则用mid砍断分开左孩子右孩子来找
            {
               line_insert(p<<1,a,mid);
               line_insert(p<<1|1,mid,b);                  
            }
}
void cnt(int p)
{
  cout<<"=========                                 p d[p].a d[p].b "<<d[p].a<<' '<<d[p].b<<endl;
  if (d[p].cover==1)
   {   
     cout<<"p d[p].a d[p].b "<<d[p].a<<' '<<d[p].b<<endl;
     sum+=(d[p].b-d[p].a);//一开始只是sum++而已,晕
     return;
   }
  if(d[p].a+1==d[p].b)//用这个控制到叶子节点已经足够
       return;
  //else{
         //if((p<<1)<=((m-1)<<1-1) )
           cnt(p<<1);
         //if((p<<1|1)<=((m-1)<<1-1))
           cnt(p<<1|1);
 //     }
}
int main()
{
   
int test;
cin>>test;
while(test--)
{
 
  cin>>n>>m;
  make_tree(1,1,m);//1,是数组的第一个数。1是数轴的开端,m末端
  
  int aa,bb;
  for(int i=0;i<n;i++)
  {
    cin>>aa>>bb;
    line_insert(1,aa,bb);//每输入一对数据,就要更新二叉树
  /*  sum=0;
    cnt(1);
    cout<<sum<<endl;   */    
  }
  sum=0;
  cnt(1);
  cout<<sum<<endl;           
}
system("pause");
return 0; }

总结:线段树就是初始化一棵二叉树,然后通过插入进行更新二叉树的信息,最后再进行统计