線段樹小節

哎~由於智力因素,線段樹看了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. };


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章