哎~由于智力因素,线段树看了N个星期,今天终于看懂了(只是停留在看懂的阶段,还不是用的很熟练)。
线段树的数据结构:
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。
---------------------------------------------线段树的完整代码--------------------------------------------------
线段树的数据结构:
- const int SIZE = 10010;
- const double EPS = 1e-6;
- int MAX = 99999999;
- struct node // the node of line tree
- {
- int i,j; // 区间范围
- node * lson;
- node * rson;
- int count; // 线段覆盖条数
- int m; // 测度
- int line; // 连续段数
- int lbd,rbd; // 用来计算连续段数
- node(int l,int r)
- {
- i = l,j = r;
- count = m = line = lbd = rbd = 0;
- lson = rson = NULL;
- }
- };
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。
---------------------------------------------线段树的完整代码--------------------------------------------------
- struct node // the node of line tree
- {
- int i,j; // 区间范围
- node * lson;
- node * rson;
- int count; // 线段覆盖条数
- int m; // 测度
- int line; // 连续段数
- int lbd,rbd; // 用来计算连续段数
- node(int l,int r)
- {
- i = l,j = r;
- count = m = line = lbd = rbd = 0;
- lson = rson = NULL;
- }
- };
- class LineTree
- {
- node * head;
- /* 以下函数内部使用,可不用考虑 */
- void init(node * pnode = NULL)
- {
- head = pnode;
- }
- void updateM()
- {
- if (head->count > 0) // 被覆盖满
- head->m = head->j - head->i;
- else if (head->j - head->i == 1) // 该节点为叶节点
- head->m = 0;
- else // 其他内部节点的情况
- head->m = (head->lson)->m + (head->rson)->m;
- }
- void updateLine()
- {
- if (head->count > 0)
- head->lbd = head->rbd = head->line = 1;
- else if (head->j - head->i == 1)
- head->lbd = head->rbd = head->line = 0;
- else
- {
- head->lbd = (head->lson)->lbd;
- head->rbd = (head->rson)->rbd;
- head->line = (head->lson)->line + (head->rson)->line - (head->lson)->rbd * (head->rson)->lbd;
- }
- }
- public:
- LineTree()
- {
- head = NULL;
- }
- void clear() // 清空线段数
- {
- if(head == NULL)
- return;
- LineTree temp;
- temp.init(head->lson);
- temp.clear();
- temp.init(head->rson);
- temp.clear();
- delete head;
- head = NULL;
- }
- void build(int l,int r) // 建立线段树,区间[l,r]
- {
- head = new node(l,r);
- if (r - l > 1)
- {
- int k = (l + r) / 2;
- LineTree temp;
- temp.build(l,k);
- head->lson = temp.head;
- temp.init();
- temp.build(k,r);
- head->rson = temp.head;
- }
- }
- void insert(int l,int r) // 插入一条线段
- {
- if (l <= head->i && r >= head->j)
- (head->count)++;
- else
- {
- LineTree temp;
- if (l < (head->i+head->j)/2)
- {
- temp.init(head->lson);
- temp.insert(l,r);
- }
- if (r > (head->i+head->j)/2)
- {
- temp.init(head->rson);
- temp.insert(l,r);
- }
- }
- updateM();
- updateLine();
- }
- void del(int l,int r) // 删除一条线段
- {
- if (l <= head->i && head->j <= r)
- (head->count)--;
- else
- {
- LineTree temp;
- if (l < (head->i+head->j)/2)
- {
- temp.init(head->lson);
- temp.del(l,r);
- }
- if (r > (head->i+head->j)/2)
- {
- temp.init(head->rson);
- temp.del(l,r);
- }
- }
- updateM();
- updateLine();
- }
- int GetM() // 测度
- {
- return head->m;
- }
- int GetLine() // 连续段数
- {
- return head->line;
- }
- int GetCov() // 覆盖线段数
- {
- return head->count;
- }
- ~LineTree() {}
- };

本文深入浅出地介绍了线段树这一高效数据结构,包括其基本概念、数据成员及功能意义,并给出了完整的线段树实现代码。通过阅读本文,读者可以了解如何使用线段树解决区间查询和更新问题。
3万+

被折叠的 条评论
为什么被折叠?



