【线段树】框架

 往往线段树题目会有自己的要求,比如分治——力扣399周赛 . - 力扣(LeetCode)

这个时候是需要根据题目去改线段树的。

具体线段树原理可以看我的文章 线段树1板子 区间加-CSDN博客

以及其他成熟代码:

线段树2板子 区间加与乘-CSDN博客

P6242 【模板】线段树 3(区间最值操作、区间历史最值)-CSDN博客

注意,线段树节点是从1开始的,维护的区间可以不是。

构造里可以改build_tree范围。

int构造:

 
class ST//segment tree
{
	struct node
	{
		ll val;
		int l, m, r;
		node(int v = 0) :val(v), l(0), m(0), r(0)
		{}
	};
	int aiml, aimr;
	int val;
 
	int n;
	vector<int>a;
	vector<node>d;
	void build_tree(int i, int l, int r)
	{
		d[i].l = l, d[i].m = l + (r - l) / 2, d[i].r = r;
		if (l == r)
		{
			d[i].val = a[l] ;
			return;
		}
		build_tree(i * 2, l, d[i].m);
		build_tree(i * 2 + 1, d[i].m + 1, r);
		push_up(i);
	}
	void push_up(int i)
	{
		d[i].val = (d[i * 2].val + d[i * 2 + 1].val) ;
	}
	void push_down(int i)
	{
		auto& lchild = d[i * 2], & rchild = d[i * 2 + 1];
	}
	ll _getsum(int i)
	{
		if (d[i].l > aimr || d[i].r < aiml)return 0;
		if (aiml <= d[i].l && d[i].r <= aimr)return d[i].val;
 
		//push_down(i);
 
		return (_getsum(i * 2) + _getsum(i * 2 + 1)) ;
	}
	ll _getmax(int i)
	{
		if (d[i].l > aimr || d[i].r < aiml)return LLONG_MIN;
		if (aiml <= d[i].l && d[i].r <= aimr)return d[i].val;
 
		//push_down(i);
 
		return max(_getmax(i * 2), _getmax(i * 2 + 1));
	}
	void _update1(int i)
	{
		if (d[i].l > aimr || d[i].r < aiml)return;
		if (aiml <= d[i].l && d[i].r <= aimr)
		{
			d[i].val = (d[i].val + val * (d[i].r - d[i].l + 1));
			return;
		}
 
		//push_down(i);//因为要向下搜了,所以把当前的懒标记给下面兑现一下
 
		_update1(i * 2);
		_update1(i * 2 + 1);
		//push_up(i);
	}
public:
	ll getsum(int l, int r)
	{
		aiml = l, aimr = r;
		return _getsum(1);
	}
	ll getmax(int l, int r)
	{
		aiml = l, aimr = r;
		return _getmax(1);
    }
	void update1(int l, int r, ll val)
	{
		aiml = l, aimr = r;
		this->val = val;
		_update1(1);//加并挂标记
	}
	ST(vector<int>arr)
	{
		a = arr;
		n = a.size() - 1;
		d = vector<node>(4 * n);
		build_tree(1, 1, n);
		a = {};//清空a数组
	}
};

ll构造:

 
class ST//segment tree
{
	struct node
	{
		ll val;
		int l, m, r;
		node(int v = 0) :val(v), l(0), m(0), r(0)
		{}
	};
	int aiml, aimr;
	int val;
 
	int n;
	vector<ll>a;
	vector<node>d;
	void build_tree(int i, int l, int r)
	{
		d[i].l = l, d[i].m = l + (r - l) / 2, d[i].r = r;
		if (l == r)
		{
			d[i].val = a[l] ;
			return;
		}
		build_tree(i * 2, l, d[i].m);
		build_tree(i * 2 + 1, d[i].m + 1, r);
		push_up(i);
	}
	void push_up(int i)
	{
		d[i].val = (d[i * 2].val + d[i * 2 + 1].val) ;
	}
	void push_down(int i)
	{
		auto& lchild = d[i * 2], & rchild = d[i * 2 + 1];
	}
	ll _getsum(int i)
	{
		if (d[i].l > aimr || d[i].r < aiml)return 0;
		if (aiml <= d[i].l && d[i].r <= aimr)return d[i].val;
 
		//push_down(i);
 
		return (_getsum(i * 2) + _getsum(i * 2 + 1)) ;
	}
	ll _getmax(int i)
	{
		if (d[i].l > aimr || d[i].r < aiml)return LLONG_MIN;
		if (aiml <= d[i].l && d[i].r <= aimr)return d[i].val;
 
		//push_down(i);
 
		return max(_getmax(i * 2), _getmax(i * 2 + 1));
	}
	void _update1(int i)
	{
		if (d[i].l > aimr || d[i].r < aiml)return;
		if (aiml <= d[i].l && d[i].r <= aimr)
		{
			d[i].val = (d[i].val + val * (d[i].r - d[i].l + 1));
			return;
		}
 
		//push_down(i);//因为要向下搜了,所以把当前的懒标记给下面兑现一下
 
		_update1(i * 2);
		_update1(i * 2 + 1);
		//push_up(i);
	}
public:
	ll getsum(int l, int r)
	{
		aiml = l, aimr = r;
		return _getsum(1);
	}
	ll getmax(int l, int r)
	{
		aiml = l, aimr = r;
		return _getmax(1);
    }
	void update1(int l, int r, ll val)
	{
		aiml = l, aimr = r;
		this->val = val;
		_update1(1);//加并挂标记
	}
	ST(vector<ll>arr)
	{
		a = arr;
		n = a.size() - 1;
		d = vector<node>(4 * n);
		build_tree(1, 1, n);
		a = {};//清空a数组
	}
};

练习:

感觉洛谷的模板1对于初学者来说太快了,因为区间加要懒标记优化。

这里有几道单点修改的题(力扣周赛压轴题),甚至可以手搓:

387周赛:. - 力扣(LeetCode)

399周赛:. - 力扣(LeetCode)

131双周赛:. - 力扣(LeetCode)

402周赛:. - 力扣(LeetCode)

  • 4
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值