Дерево отрезков



Дерево отрезков - структура данных, предназначенная для быстрого выполнения запросов о состоянии какого-либо интервала последовательности.


Листинг C++

/*
Дерево отрезков
*/
class segments_tree
{
public:
	int l, r;
	int Max, Min, Sum;
	int count_min, count_max;
	int add;

	segments_tree *left;
	segments_tree *right;

	segments_tree(int _l, int _r);
	void modify(int _l, int _r, int value);
	int maximum(int _l, int _r);
	int minimum(int _l, int _r);
	int sum(int _l, int _r);
	int count_minimal(int _l, int _r);
	int count_maximal(int _l, int _r);
};
// Конструктор дерева
segments_tree :: segments_tree(int _l, int _r)
{
	l = _l;
	r = _r;
	Max = 0;
	Min = 0;
	Sum = 0;
	count_min = (_r - _l + 1);
	count_max = (_r - _l + 1);
	add = 0;
	left = NULL;
	right = NULL;
	if (l < r)
	{
		left = new segments_tree(l, (l + r) / 2);
		right = new segments_tree((l + r) / 2 + 1, r);
	}
}
// Добавление ко всем элементам с _l по _r числа value
void segments_tree :: modify(int _l, int _r, int value)
{
	if (l == _l && r == _r)
		add += value;
	else
	{
		if (_l <= left->r)
			left->modify(_l, min(_r, left->r), value);
		if (_r >= right->l)
			right->modify(max(_l, right->l), _r, value);
		
		Max = max(left->Max + left->add, right->Max + right->add);
		Min = min(left->Min + left->add, right->Min + right->add);
		Sum = left->Sum + left->add * (left->r - left->l + 1) + 
			right->Sum + right->add * (right->r - right->l + 1);
		
		count_min = 0;
		if (left->Min + left->add == Min)
			count_min += left->count_min;
		if (right->Min + right->add == Min)
			count_min += right->count_min;
		
		count_max = 0;
		if (left->Max + left->add == Max)
			count_max += left->count_max;
		if (right->Max + right->add == Max)
			count_max += right->count_max;
	}
}
// Максимальное число из [_l, _r]
int segments_tree :: maximum(int _l, int _r)
{
	if (l == _l && r == _r)
		return Max + add;
	int res = - 1e7;
	if (_l <= left->r)
		res = max(res, left->maximum(_l, min(_r, left->r)) + add);
	if (_r >= right->l)
		res = max(res, right->maximum(max(_l, right->l), _r) + add);
	return res;
}
// Минимальное число из [_l, _r]
int segments_tree :: minimum(int _l, int _r)
{
	if (l == _l && r == _r)
		return Min + add;
	int res = 1e7;
	if (_l <= left->r)
		res = min(res, left->minimum(_l, min(_r, left->r)) + add);
	if (_r >= right->l)
		res = min(res, right->minimum(max(_l, right->l), _r) + add);
	return res;
}
// Сумма всех чисел из [_l, _r]
int segments_tree :: sum(int _l, int _r)
{
	if (l == _l && r == _r)
		return Sum + add * (_r - _l + 1);
	int res = 0;
	if (_l <= left->r)
		res += left->sum(_l, min(_r, left->r));
	if (_r >= right->l)
		res += right->sum(max(_l, right->l), _r);
	return res + add * (_r - _l + 1);
}
// Количество минимальных элементов в [_l, _r]
int segments_tree :: count_minimal(int _l, int _r)
{
	if (l == _l && r == _r)
		return count_min;
	int res = 0;
	if (_l <= left->r && left->Min + left->add == Min)
		res += left->count_minimal(_l, min(_r, left->r));
	if (_r >= right->l && right->Min + right->add == Min)
		res += right->count_minimal(max(_l, right->l), _r);
	return res;
}
// Количество максимальных элементов в [_l, _r]
int segments_tree :: count_maximal(int _l, int _r)
{
	if (l == _l && r == _r)
		return count_max;
	int res = 0;
	if (_l <= left->r && left->Max + left->add == Max)
		res += left->count_maximal(_l, min(_r, left->r));
	if (_r >= right->l && right->Max + right->add == Max)
		res += right->count_maximal(max(_l, right->l), _r);
	return res;
}

Создан 09.12.2007, 19:44
Изменён 15.01.2011, 18:46


По всем вопросам обращаться: rumterg@gmail.com