您的位置:首页 > 其它

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

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



这道题目是一个经典的模型。在这里,我们略去某些处理的步骤,直接分析重点问题,可以把题目抽象地描述如下: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; }

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

 

 

 

 
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  insert tree struct system ini