线段树(segment tree) code

线段树(segment tree)


线段树是一棵二叉树,记为T(a, b),参数a,b表示区间[a,b],其中b-a称为区间的长度,记为L。

线段树T(a,b)递归定义类似为:

若L>1 :  [a, (a+b) div 2]为 T的左儿子;

             [(a+b) div 2,b]为T 的右儿子。 

若L=1 : T为叶子节点。

上面的线段树只是一种可能的形式,具体按自己的需求定义,只要保证父节点“覆盖”所有的子节点


例:

桌子上零散地放着若干个盒子,桌子的后方是一堵墙。如图所示。现在从桌子的前方射来一束平行光, 把盒子的影子投射到了墙上。问影子的总宽度是多少?

这道题目是一个经典的模型。在这里,我们略去某些处理的步骤,直接分析重点问题,可以把题目抽象地描述如下:x轴上有若干条线段,求线段覆盖的总长度,即S1+S2的长度。


code:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

typedef struct Node
{
	int lvalue, rvalue;
	int data;
	struct Node *lchild;
	struct Node *rchild;	
} Node;

Node  *Build(int l, int r)
{
	Node *root;

	if (l >= r)
		return NULL;
		
	root = (Node *)calloc(1, sizeof(Node));
	root->lvalue = l;
	root->rvalue = r;
	root->data = 0;
	root->lchild = NULL;
	root->rchild = NULL;

	if (l + 1 < r) {
		int  mid = (l + r) >> 1;
		root->lchild = Build(l , mid) ;
		root->rchild = Build(mid , r) ; 
	} 

	return root; 
}

void  Insert(Node *root, int c, int d)
{
	if (!root)
		return;
		
	if(c <= root->lvalue && d >= root->rvalue) 
		root->data++;
	else {
		int mid = (root->lvalue + root->rvalue) >> 1;
		if (d <= mid) 
			Insert(root->lchild, c, d);
		else if(c >= mid) 
			Insert(root->rchild, c, d);
		else {
			Insert(root->lchild, c, mid);
			Insert(root->rchild, mid, d);
		}
	}
} 



void  Delete(Node *root, int c, int d)
{
	if (!root)
		return;
		
	if (c <= root->lvalue && d >= root->rvalue) 
		root->data--;
	else 
	{
		int mid = (root->lvalue + root->rvalue) >> 1;
		if (d <= mid) 
			Delete(root->lchild, c, d);
		else if(c >= mid) 
			Delete(root->rchild, c, d);
		else {
			Delete(root->lchild, c, mid);
			Delete(root->rchild, mid, d);
		}
	}
} 

void Find(Node *root,int a,int b, int *count)  
{  
	int mid;
	
	if (!root)
		return;
	
	if(root->data > 0) {
		*count += (root->rvalue - root->lvalue);  
		return;  
	}
	
	mid = (root->lvalue + root->rvalue) >> 1;  
	if(b <= mid)   
		Find(root->lchild, a, b, count);  
	else if(a >= mid)   
		Find(root->rchild,a, b, count);	
	else {  
		Find(root->lchild, a, mid, count);  
		Find(root->rchild, mid, b, count);  
	}  
}

int value[][2] = {
		{1, 7},
		{8, 17},
		{15, 23},
		{34, 40},
		{38, 42},
		{36, 41}
	};
	
int main()
{
	int count = 0;
	int i;
	
	Node *root = Build(9, 101);
	
	for (i = 0; i < sizeof(value) / sizeof(value[0]); i++)
		Insert(root, value[i][0], value[i][1]);
		
	Find(root, 4, 50, &count);
	printf("count: %d\n", count);
	
	Delete(root, 36, 41);
	
	count = 0;
	Find(root, 4, 50, &count);
	printf("count: %d\n", count);
	
	Delete(root, 38, 42);
	
	count = 0;
	Find(root, 4, 50, &count);
	printf("count: %d\n", count);
	
	return 0;
}




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值