线段树 (多套件 | 区间维护 | 二分 | 可持久化 )

本文详细介绍了使用C++实现的区间树(SegTree)结构,包括递归构建、区间和/最小值维护、区间加法、查询功能以及计数器的处理。
摘要由CSDN通过智能技术生成
#include <stdio.h>
#include <iostream>
#include <stdlib.h>
#include <math.h>
#include <stdbool.h>
#include <string.h>
#include <limits.h>
#define LftChild(x) ((x)<<1)
#define RghtChild(x) (((x)<<1)+1)
#define min(a,b) (((a)<(b))?(a):(b))
#define ROOT 1
static const int MAXN = (int)(1e6);
typedef int ElemType;
typedef struct SegTree{
	ElemType RawArr[MAXN+1];
	ElemType SegArr[(MAXN<<2)+1];
	ElemType Tag[(MAXN<<2)+1];
	int Cnt[(MAXN<<2)+1];
	int N;
	int Depth;
}SegTree,*ptrToSegTree;

namespace UpdFncKit{
	//更新组件
	//维护区间和 
	void UpdSum(int *SegSumArr,int x)
	{
		SegSumArr[x]=SegSumArr[LftChild(x)]+SegSumArr[RghtChild(x)];
	}
	//维护区间最值 
	void UpdMin(int *SegMinArr,int x)
	{
		SegMinArr[x] = min(SegMinArr[LftChild(x)],SegMinArr[RghtChild(x)]);
	}
	//维护区间最值和计数器 
	void UpdMinWithCnt(int *SegMinArr,int *Cnt,int x)
	{
		SegMinArr[x] = min(SegMinArr[LftChild(x)],SegMinArr[RghtChild(x)]);
		if(SegMinArr[LftChild(x)] == SegMinArr[RghtChild(x)]) Cnt[x]=Cnt[LftChild(x)]+Cnt[RghtChild(x)];
		else if(SegMinArr[LftChild(x)] <= SegMinArr[RghtChild(x)])Cnt[x] = Cnt[LftChild(x)];
		else Cnt[x] = Cnt[RghtChild(x)];
	}
}
namespace MergeFncKit{
	//区间查询配套组件 
	//初始值+合并逻辑 
	const int INIT_SEG_SUM = 0;
	//维护区间和 
	ElemType MergeSum(ElemType sum_1,ElemType sum_2)
	{
		return sum_1+sum_2;
	}
	
	const int INIT_SEG_MIN = INT_MAX;
	const std::pair<ElemType,int> INIT_SEG_MIN_PAIR = {INT_MAX,0};
	//维护区间最小值 
	ElemType MergeMin(ElemType min_1,ElemType min_2)
	{
		return min(min_1,min_2);
	}
	//维护区间最小值以及计数器 
	std::pair<ElemType,int> MergeMinWithCnt(const std::pair<ElemType,int> &p,const std::pair<ElemType ,int> &q)
	{
		if(p.first == q.first)return {p.first,p.second+q.second};
		if(p.first <= q.first)return p;
		return q;
	}
}

namespace SegmTagDownFncKit{
	void SegmSumEqualTagDown(int *SegSumArr,int *Tag,int Lft,int Rght,int Beg,int End,int x,int v)
	{
		//区间赋值操作
		//维护区间和 
		if(Beg<=Lft && Rght<=End)
		{
			Tag[x] = v;
			SegSumArr[x] = (Rght-Lft+1)*v;
		}else if(Tag[x]>0){
			int Mid = Lft+((Rght-Lft)>>1);
			Tag[LftChild(x)] = Tag[RghtChild(x)] = Tag[x];
			Tag[x] = 0;
			SegSumArr[LftChild(x)] = (Mid-Lft+1)*Tag[x];
			SegSumArr[RghtChild(x)] = (Rght-Mid)*Tag[x];
		}
	}
	void SegmSumPlusTagDown(int *SegSumArr,int *Tag,int Lft,int Rght,int Beg,int End,int x,int v)
	{
		//区间加操作
		//维护区间和 
		if(Beg<=Lft && Rght<=End)
		{
			Tag[x] += v;
			SegSumArr[x] += (Rght-Lft+1)*v;
			
		}else if(Tag[x]>0){
			int Mid = Lft+((Rght-Lft)>>1);
			
			Tag[LftChild(x)] += Tag[x];Tag[RghtChild(x)]+=Tag[x];
			Tag[x] = 0;
			SegSumArr[LftChild(x)] += (Mid-Lft+1)*Tag[x];
			SegSumArr[RghtChild(x)] += (Rght-Mid)*Tag[x];
		}
	}
	void SegmMinPlusTagDown(int *SegMinArr,int *Tag,int Lft,int Rght,int Beg,int End,int x,int v)
	{
		//区间加操作 
		//维护最小值 
		 if(Beg<=Lft && Rght<=End)
		{
			Tag[x] += v;
			SegMinArr[x] += (Rght-Lft+1)*v;
			
		}else if(Tag[x]>0){
			Tag[LftChild(x)] += Tag[x];Tag[RghtChild(x)]+=Tag[x];
			SegMinArr[LftChild(x)] += Tag[x];
			SegMinArr[RghtChild(x)] += Tag[x];
			Tag[x] = 0;
		}
	}
}

static void _Build(ptrToSegTree pt,int x,int Lft,int Rght,void(*UPD)(int *SegArr,int x));
static void Build(ptrToSegTree pt,void(*UPD)(int *SegArr,int x))
{
	pt->Depth = (int)log(pt->N) + 1;
	_Build(pt,ROOT,1,pt->N,UPD);
}
static void _Build(ptrToSegTree pt,int x,int Lft,int Rght,void(*UPD)(int *SegArr,int x))
{
	if(Lft == Rght){pt->SegArr[x] = pt->RawArr[x];return;}
 	int Mid = Lft+((Rght-Lft)>>1);
 	_Build(pt,LftChild(x),Lft,Mid,UPD);
 	_Build(pt,RghtChild(x),Mid+1,Rght,UPD);
 	UPD(pt->SegArr,x);
}

static ElemType _Query(ptrToSegTree pt,
						int Beg,int End,int x,int Lft,int Rght,
						ElemType(*Merge)(ElemType,ElemType),ElemType INIT,
						void(*SegmTagDown)(int *Tag,int *SegArr,int Lft,int Rght,int x,int v)
						);
static ElemType Query(ptrToSegTree pt,
					int Beg,int End,ElemType(*Merge)(ElemType,ElemType),ElemType INIT,
					void(*SegmTagDown)(int *Tag,int *SegArr,int Lft,int Rght,int x,int v))
{
	return _Query(pt,Beg,End,ROOT,1,pt->N,Merge,INIT,SegmTagDown);
}
static ElemType _Query(ptrToSegTree pt,
						int Beg,int End,int x,int Lft,int Rght,
						ElemType(*Merge)(ElemType,ElemType),ElemType INIT,
						void(*SegmTagDown)(int *Tag,int *SegArr,int Lft,int Rght,int x,int v))
{
	if(Beg<=Lft && Rght <= End)return pt->SegArr[x];
	SegmTagDown(pt->Tag,pt->SegArr,Lft,Rght,x,pt->Tag[x]);
 	int Mid = Lft+((Rght-Lft)>>1);
 	ElemType LftVal = INIT,RghtVal = INIT;
	if(Beg <= Mid)LftVal = Merge(INIT,LftVal);
	if(End > Mid)RghtVal = Merge(INIT,RghtVal);
	return Merge(LftVal,RghtVal);
}

static void _SingMod(ptrToSegTree pt,
					int p,int v,int Lft,int Rght,int x,
					void(*UPD)(int *SegArr,int x));
static void SingMod(ptrToSegTree pt,int p,int v,void(*UPD)(int *SegArr,int x))
{
	_SingMod(pt,p,v,1,pt->N,ROOT,UPD);	
}
static void  _SingMod(ptrToSegTree pt,
					int p,int v,int Lft,int Rght,int x,
					void(*UPD)(int *SegArr,int x))
{
	if(Lft == Rght){pt->SegArr[x] = v;return;}
 	int Mid = Lft+((Rght-Lft)>>1);
 	if(p<=Mid)_SingMod(pt,p,v,Lft,Mid,LftChild(x),UPD);
 	else _SingMod(pt,p,v,Mid+1,Rght,RghtChild(x),UPD);
 	UPD(pt->SegArr,x);
}

static void _SectMod(ptrToSegTree pt,
					int Beg,int End,int Lft,int Rght,int v,int x,
					void(*SegmTagDown)(int *Tag,int *SegArr,int Lft,int Rght,int Beg,int End,int x,int v),
					void(*UPD)(int *SegArr,int x));
static void SectMod(ptrToSegTree pt,
					int Beg,int End,int v,
					void(*SegmTagDown)(int *SegArr,int *Tag,int Lft,int Rght,int Beg,int End,int x,int v),
					void(*UPD)(int *SegArr,int x))
{
	_SectMod(pt,Beg,End,1,pt->N,v,ROOT,SegmTagDown,UPD);
} 
static void _SectMod(ptrToSegTree pt,
					int Beg,int End,int Lft,int Rght,int v,int x,
					void(*SegmTagDown)(int *SegArr,int *Tag,int Lft,int Rght,int Beg,int End,int x,int v),
					void(*UPD)(int *SegArr,int x))
{
	SegmTagDown(pt->SegArr,pt->Tag,Lft,Rght,Beg,End,x,v);
	if(Beg<=Lft && End <= Rght)return;
	int Mid = Lft+((Rght-Lft)>>1);
	if(Beg <= Mid)
		_SectMod(pt,Beg,End,Lft,Mid,v,LftChild(x),SegmTagDown,UPD);
	if(End>Mid) 
		_SectMod(pt,Beg,End,Mid+1,Rght,v,RghtChild(x),SegmTagDown,UPD);
	UPD(pt->SegArr,x);
}

static std::pair<ElemType,int> _QueryMinWithCnt(ptrToSegTree pt,
					int Beg,int End,int Lft,int Rght,int x,
					const std::pair<ElemType,int> &INIT,
					std::pair<ElemType,int> MergeMinWithCnt(const std::pair<ElemType,int> &p,const std::pair<ElemType ,int> &q),
					void(*SegmTagDown)(int *Tag,int *SegArr,int Lft,int Rght,int x,int v)
					);
static std::pair<ElemType,int> QueryMinWithCnt(ptrToSegTree pt,
					int Beg,int End,
					const std::pair<ElemType,int> &INIT,
					std::pair<ElemType,int> MergeMinWithCnt(const std::pair<ElemType,int> &p,const std::pair<ElemType ,int> &q),
					void(*SegmTagDown)(int *Tag,int *SegArr,int Lft,int Rght,int x,int v))
{
	std::pair<ElemType,int> retp = _QueryMinWithCnt(pt,Beg,End,1,pt->N,ROOT,INIT,MergeMinWithCnt,SegmTagDown);
	return retp;
}
static std::pair<ElemType,int> _QueryMinWithCnt(ptrToSegTree pt,
					int Beg,int End,int Lft,int Rght,int x,
					const std::pair<ElemType,int> &INIT,
					std::pair<ElemType,int> MergeMinWithCnt(const std::pair<ElemType,int> &p,const std::pair<ElemType ,int> &q),
					void(*SegmTagDown)(int *Tag,int *SegArr,int Lft,int Rght,int x,int v)
					)
{
	if(Beg <= Lft && Rght >= End)return {pt->SegArr[x],pt->Cnt[x]};
	SegmTagDown(pt->Tag,pt->SegArr,Lft,Rght,x,pt->Tag[x]);
	int Mid = Lft+((Rght-Lft)>>1);
	std::pair<ElemType,int> LftPair = MergeMinWithCnt(INIT,_QueryMinWithCnt(pt,Beg,End,Lft,Mid,LftChild(x),INIT,MergeMinWithCnt,SegmTagDown));
	std::pair<ElemType,int> RghtPair = MergeMinWithCnt(INIT,_QueryMinWithCnt(pt,Beg,End,Mid+1,Rght,RghtChild(x),INIT,MergeMinWithCnt,SegmTagDown));
	return MergeMinWithCnt(LftPair,RghtPair);
}

  • 8
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

XNB's Not a Beginner

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值