线段树小节

本文深入浅出地介绍了线段树这一高效数据结构,包括其基本概念、数据成员及功能意义,并给出了完整的线段树实现代码。通过阅读本文,读者可以了解如何使用线段树解决区间查询和更新问题。
哎~由于智力因素,线段树看了N个星期,今天终于看懂了(只是停留在看懂的阶段,还不是用的很熟练)。
线段树的数据结构:
  1. const int SIZE = 10010;
  2. const double EPS = 1e-6;
  3. int MAX = 99999999;
  4. struct node // the node of line tree
  5. {
  6.     int i,j; // 区间范围
  7.     node * lson;
  8.     node * rson;
  9.     int count; // 线段覆盖条数
  10.     int m; // 测度
  11.     int line; // 连续段数
  12.     int lbd,rbd; // 用来计算连续段数
  13.     node(int l,int r)
  14.     {
  15.         i = l,j = r;
  16.         count = m = line = lbd = rbd = 0;
  17.         lson = rson = NULL;
  18.     }
  19. };
count:线段覆盖条数,当插入线段完全覆盖线段树上的区间时( l<=NODE.i && NODE.j<=r ),count才增长,否则,就将该线段插入到子节点中。
m:测度,通俗点说,就是该区间中被覆盖过线段的总长度。当该区间的count>1时,m等于该区间的长度,如果是离散化之后的线段树,就加上对应的线段的长度。如果这个节点不是内部节点而是叶节点并且count=0,那m就等于0。如果这个节点的count等于0,但是他是内部节点,那么m就等于他左右子节点的m值的和。
line连续段数:就是该区间上连续线段的条数,比如线段树[1,10]上,有两条线段[1,5],[8,10],那么[1,10]这个区间上的连续线段的条数就是2;如果有两条线段是[1,5],[5,10],那么该区间上连续线段条数就是1。由此可以看出,连续线段条数,与该节点的左右子节点上的左右端点的覆盖情况有关,因此还有设立2个域lbd,rbd表示该区间的左右端点的覆盖情况。假如count>0,说明这个区间被一条线段覆盖了,那么显然这个区间的line等于1;假如这个节点是叶节点并且count=0,那么line显然等于0;假如这个区间的count=0但是他是内部节点,就又要分2种情况:①左子节点的rbd和右子节点lbd都等于1,即上例中[1,5],[5,10]的情况,那么line就等于1。 ②左子节点的rbd和右子节点lbd至少有1个不等于1,即上例中[1,5],[8,10]的情况,那么line就等于2。对于lbd,rbd的定义,可以这样该区间的lbd等于他的左子节点的lbd,rbd等于他的右子节点的rbd。
---------------------------------------------线段树的完整代码--------------------------------------------------
  1. struct node // the node of line tree
  2. {
  3.     int i,j; // 区间范围
  4.     node * lson;
  5.     node * rson;
  6.     int count; // 线段覆盖条数
  7.     int m; // 测度
  8.     int line; // 连续段数
  9.     int lbd,rbd; // 用来计算连续段数
  10.     node(int l,int r)
  11.     {
  12.         i = l,j = r;
  13.         count = m = line = lbd = rbd = 0;
  14.         lson = rson = NULL;
  15.     }
  16. };
  17. class LineTree
  18. {
  19.     node * head;
  20.     /* 以下函数内部使用,可不用考虑 */
  21.     void init(node * pnode = NULL)
  22.     {
  23.         head = pnode;
  24.     }
  25.     void updateM()
  26.     {
  27.         if (head->count > 0) // 被覆盖满
  28.             head->m = head->j - head->i;
  29.         else if (head->j - head->i == 1) // 该节点为叶节点
  30.             head->m = 0;
  31.         else    // 其他内部节点的情况
  32.             head->m = (head->lson)->m + (head->rson)->m;
  33.     }
  34.     void updateLine()
  35.     {
  36.         if (head->count > 0)
  37.             head->lbd = head->rbd = head->line = 1;
  38.         else if (head->j - head->i == 1)
  39.             head->lbd = head->rbd = head->line = 0;
  40.         else
  41.         {
  42.             head->lbd = (head->lson)->lbd;
  43.             head->rbd = (head->rson)->rbd;
  44.             head->line = (head->lson)->line + (head->rson)->line - (head->lson)->rbd * (head->rson)->lbd;
  45.         }
  46.     }
  47. public:
  48.     LineTree()
  49.     {
  50.         head = NULL;
  51.     }
  52.     void clear() // 清空线段数
  53.     {
  54.         if(head == NULL)
  55.             return;
  56.         LineTree temp;
  57.         temp.init(head->lson);
  58.         temp.clear();
  59.         temp.init(head->rson);
  60.         temp.clear();
  61.         delete head;
  62.         head = NULL;
  63.     }
  64.     void build(int l,int r) // 建立线段树,区间[l,r]
  65.     {
  66.         head = new node(l,r);
  67.         if (r - l > 1)
  68.         {
  69.             int k = (l + r) / 2;
  70.             LineTree temp;
  71.             temp.build(l,k);
  72.             head->lson = temp.head;
  73.             temp.init();
  74.             temp.build(k,r);
  75.             head->rson = temp.head;
  76.         }
  77.     }
  78.     void insert(int l,int r) // 插入一条线段
  79.     {
  80.         if (l <= head->i && r >= head->j)
  81.             (head->count)++;
  82.         else
  83.         {
  84.             LineTree temp;
  85.             if (l < (head->i+head->j)/2)
  86.             {
  87.                 temp.init(head->lson);
  88.                 temp.insert(l,r);
  89.             }
  90.             if (r > (head->i+head->j)/2)
  91.             {
  92.                 temp.init(head->rson);
  93.                 temp.insert(l,r);
  94.             }
  95.         }
  96.         updateM();
  97.         updateLine();
  98.     }
  99.     void del(int l,int r) // 删除一条线段
  100.     {
  101.         if (l <= head->i && head->j <= r)
  102.             (head->count)--;
  103.         else
  104.         {
  105.             LineTree temp;
  106.             if (l < (head->i+head->j)/2)
  107.             {
  108.                 temp.init(head->lson);
  109.                 temp.del(l,r);
  110.             }
  111.             if (r > (head->i+head->j)/2)
  112.             {
  113.                 temp.init(head->rson);
  114.                 temp.del(l,r);
  115.             }
  116.         }
  117.         updateM();
  118.         updateLine();
  119.     }
  120.     int GetM() // 测度
  121.     {
  122.         return head->m;
  123.     }
  124.     int GetLine() // 连续段数
  125.     {
  126.         return head->line;
  127.     }
  128.     int GetCov() // 覆盖线段数
  129.     {
  130.         return head->count;
  131.     }
  132.     ~LineTree() {}
  133. };


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值