线段树

来源:互联网 发布:手机电话薄数据恢复 编辑:程序博客网 时间:2024/05/03 22:52

      对于线段树,那说明是由线段与树结合起来考虑!线段树是建立在线段的基础之上,每一个节点代表一条线段[a,b],长度为1的线段成为元线段,非元线段root都有两个子节点,左节点代表的线段为[a,(a+b)/2],编号为2*root;右节点代表的线段为[(a+b)/2+1,b],编号为2*root+1;

      线段树的特点有四点如下:

      (1):线段树是建立在线段之上,每一个节点代表一条线段[a,b];

      (2):线段树是一种二叉树的结构,操作都是递归的;

      (3):线段树是一种基于分治思想的数据结构,把问题实例划分成子实例,并分别递归的解决每一个实例,最后把子实例的解组合起来。

      (4):把线段组织成树,在树中对线段进行操作。

      线段树的储存结构一般都是用顺序储存结构,用数组保存树中的线段信息,一般结构如下:

struct node{

     int left, right, mid;

}tree[MAX];

开的空间一般都是区间范围的3倍左右。

      线段树主要适用对一个区间频繁的进行操作,然后各个区间的信息,对于不同的题目,增加不同的信息。

      线段树主要有三种操作:

    (1)建立线段树:

void build(int root,int l,int r)

{

   tree[root].l = l;

   tree[root].r = r;

   tree[root].mid = (l+r)>>1;

   if(l==r)

     return;

   build(2*root,l,tree[root].mid);//建立左子树

   build(2*root+1,tree[root].mid+1,r);//建立右子树

}

  (2)线段树的更新操作:

 为了记录节点中的线段是否被完全覆盖过,我们需要在结点中添加cover数据域,若cover=1表示此线段已经被完全覆盖过了,否则未覆盖。

void  update(int root,int l,int r)

{

 if(tree[root].l == l && tree[root].r == r)

 {

   tree[root].cover = 3;

   return;

  } 

  if(r<=tree[root].mid)

   update(l,r,2*root);

  else if (l>tree[root].mid)

   update(l,r,2*root+1);

  else

   {

    update(l,tree[root].mid,2*root);

    update(tree[root].mid+1,r,2*root+1);

    }

}

(3)线段树的统计操作:

int ans=0;

 void query(int root,int l,int r)

{

  if(tree[root].l == l && tree[root].r == r)

    ans += tree[root].cover,return;

  if(l>tree[root].mid)

   query(2*root,l,r);

  else if(r<=tree[root].mid)

   query(2*root+1,l,r);

  else

   {

     query(2*root,l,tree[root].mid);

     query(2*root+1,tree[root].mid+1,r);

   }

}

线段树要去多练习,这样才会有收获!

北大上的线段树题目有:

 POJ 1177,POJ 2182,POJ 2352,POJ 3264,POJ 3468,POJ 2777,POJ 2528,POJ 3667,POJ 1823,POJ 3368;