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

【模板】线段树 3(区间最值操作、区间历史最值) - 洛谷

目录

第一次通过版:

区间乘法可用版:  

终极版:

# 线段树框架:


第一次通过版:

#define _CRT_SECURE_NO_WARNINGS
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define endl "\n"
#define PII pair<int,int>
#define int long long

//当前节点存的懒标记是给下面用的
//spread就是给下面用的时候

//我们或许对当前最大值maxa及时的加或减了
//但是没有对maxb做操作,或者说 **某个子区间的maxb可能就没有被更新过**

//2024/4/30
//spread -> push_down
//这里保留的是向下更新前这期间的 历史最大的 标记
//
//之前“最值”的做法是错误的,懒标记频繁更新,可能就改不到最大懒标记了。 乱写,
//

//然后就是min的操作了
//不想一次改到底
//能做到改maxa时就可以停了。
//后续的maxa大于父maxa的就是要调整的
//调整多少呢?我们可以给个懒标记3

//2024/5/1
//2操作时,不过确实有多个最大值就错了

//你的老二可能比我的牢大大

//t3更新的判断有误。可能当前又变了,子节点maxa没变过。
//懂了,其实改,肯定是改大的那个;!!!我们已经递归到只改一个的时候啦!!!
//而且次大值小于修改值,即最大值仍是最大值!

//原来最大值的懒标记要分开,是为了更新maxb 。看了良久才看出来
//所以不是最大值(取min操作没取到的)也要统计maxb,所以普通懒标记也需要记录一个本次的最大 。  

//区间加u1没有及时更新 maxt1 maxt3
//

const int maxn = 5e5 + 5;
const int minv = -5e18;
//int MOD = LLONG_MAX;
class ST//segment tree
{
	struct node
	{
		ll val;//区间和
		ll maxa;//区间最大值
		ll seca;//区间次大值
		ll maxb;//区间历史最大值
		ll maxn;//最大值数目 用于最大值修改

		int t1;//加懒标记
		int maxt1;//不是最大值也要统计maxb,也需要最大懒标记
		int t2;//乘懒标记
		int t3;//最大值专属懒标记 VIP
		int maxt3;//期间最大加懒标记

		node(int v = 0) :val(v), maxa(0), seca(-2e9), maxb(0), maxn(1),
			t1(0), maxt1(0), t2(1), t3(0), maxt3(0)
		{}
	};
	int n = a.size();
	vector<ll>a;
	vector<node>d;
	void build_tree(int i, int l, int r)
	{
		if (l == r)
		{
			d[i].val = d[i].maxa = d[i].maxb = a[l];
			return;
		}
		int mid = l + (r - l) / 2;
		build_tree(i * 2, l, mid);
		build_tree(i * 2 + 1, mid + 1, r);
		push_up(i);
	}
	void push_up(int i)
	{
		d[i].val = (d[i * 2].val + d[i * 2 + 1].val);
		d[i].maxa = max(d[i * 2].maxa, d[i * 2 + 1].maxa);
		d[i].maxb = max(d[i * 2].maxb, d[i * 2 + 1].maxb);
		//不过确实有多个最大值就错了
		if (d[i * 2].maxa == d[i * 2 + 1].maxa)
		{
			d[i].seca = max(d[i * 2].seca,d[i*2+1].seca);
			d[i].maxn = d[i * 2].maxn + d[i * 2 + 1].maxn;
		}
		else if (d[i * 2].maxa > d[i * 2 + 1].maxa)
		{
			d[i].seca = max(d[i*2].seca,d[i * 2 + 1].maxa);
			d[i].maxn = d[i * 2].maxn;
		}
		else// if (d[i * 2].maxa < d[i * 2 + 1].maxa)
		{
			d[i].seca = max(d[i * 2].maxa, d[i * 2 + 1].seca);
			d[i].maxn = d[i * 2 + 1].maxn;
		}
	}
	void change(int i, int l, int r, int t1, int maxt1,int t2,int t3, int maxt3)
	{
		auto& self = d[i];

		//self.val = self.val * t2;
		//self.maxa = self.maxa * t2;
		//self.seca = self.seca * t2;
		//self.t1 *= t2;
		//self.t2 *= t2;

		self.val += t1 * (r - l + 1 - self.maxn) + t3*self.maxn;
		self.maxb = max(self.maxb, self.maxa + maxt3);
		self.maxa += t3;
		if(self.seca != -2e9)
			self.seca += t1;

		self.maxt1 = max(self.maxt1, self.t1 + maxt1);
		self.t1 += t1;
		self.maxt3 = max(self.maxt3, self.t3 + maxt3);
		self.t3 += t3;
	}
	void push_down(int i,int l,int r)
	{
		//懒惰
		int t1 = d[i].t1, maxt1 = d[i].maxt1, t2 = d[i].t2, t3 = d[i].t3, maxt3 = d[i].maxt3;
		auto& lchild = d[i * 2], &rchild = d[i * 2 + 1];
		int maxatmp = max(lchild.maxa, rchild.maxa);
		int mid = l + (r - l) / 2;

		if (lchild.maxa == maxatmp)
			change(i*2,l,mid,t1, maxt1, t2,t3,maxt3);
		else
			change(i*2,l,mid,t1, maxt1, t2,t1,maxt1);//没专属
		if (rchild.maxa == maxatmp)
			change(i * 2 + 1, mid + 1, r, t1, maxt1, t2, t3, maxt3);
		else
			change(i * 2 + 1, mid + 1, r, t1, maxt1, t2, t1, maxt1);

		//复原
		d[i].t1 = d[i].maxt1 = d[i].maxt3 = d[i].t3 = 0;
		d[i].t2 = 1;
	}
	ll _getsum(int i, int l, int r, int aiml, int aimr)
	{
		if (l > aimr || r < aiml)return 0;
		if (aiml <= l && r <= aimr)return d[i].val;

		int mid = l + (r - l) / 2;
		push_down(i,l,r);

		return _getsum(i * 2, l, mid, aiml, aimr) + _getsum(i * 2 + 1, mid + 1, r, aiml, aimr);
	}
	ll _getmaxa(int i, int l, int r, int aiml, int aimr)
	{
		if (l > aimr || r < aiml)return LLONG_MIN;
		if (aiml <= l && r <= aimr)return d[i].maxa;

		int mid = l + (r - l) / 2;
		push_down(i,l,r);

		return max(_getmaxa(i * 2, l, mid, aiml, aimr), _getmaxa(i * 2 + 1, mid + 1, r, aiml, aimr));
	}
	ll _getmaxb(int i, int l, int r, int aiml, int aimr)
	{
		if (l > aimr || r < aiml)return LLONG_MIN;
		if (aiml <= l && r <= aimr)return d[i].maxb;

		int mid = l + (r - l) / 2;
		push_down(i,l,r);

		return max(_getmaxb(i * 2, l, mid, aiml, aimr), _getmaxb(i * 2 + 1, mid + 1, r, aiml, aimr));
	}
	void _update1(int i, int l, int r, int aiml, int aimr, ll val)
	{
		if (l > aimr || r < aiml)return;
		if (aiml <= l && r <= aimr)
		{
			d[i].val = (d[i].val + val * (r - l + 1));
			d[i].maxa = d[i].maxa + val;
			d[i].maxb = max(d[i].maxb, d[i].maxa);
			if(d[i].seca != -2e9)
				d[i].seca += val;

			d[i].t1 += val;
			d[i].t3 += val;
			d[i].maxt1 = max(d[i].maxt1, d[i].t1);
			d[i].maxt3 = max(d[i].maxt3, d[i].t3);
			return;
		}

		int mid = l + (r - l) / 2;
		push_down(i,l,r);//因为要向下搜了,所以把当前的懒标记给下面兑现一下

		_update1(i * 2, l, mid, aiml, aimr, val);
		_update1(i * 2 + 1, mid + 1, r, aiml, aimr, val);
		push_up(i);
	}
	void _update2(int i, int l, int r, int aiml, int aimr, ll val)
	{
		if (l > aimr || r < aiml)return;
		if (aiml <= l && r <= aimr)
		{
			d[i].val = (d[i].val * val);
			d[i].t1 = (d[i].t1 * val);
			d[i].t2 = (d[i].t2 * val);
			return;
		}

		int mid = l + (r - l) / 2;
		push_down(i,l,r);

		_update2(i * 2, l, mid, aiml, aimr, val);
		_update2(i * 2 + 1, mid + 1, r, aiml, aimr, val);
		push_up(i);
	}
	void _update_min(int i, int l, int r, int aiml, int aimr, ll val)
	{
		if (l > aimr || r < aiml || d[i].maxa <= val)return;
		if (aiml <= l && r <= aimr && d[i].seca < val)
		{
			int k = d[i].maxa - val;

			d[i].val -= d[i].maxn* k;
			d[i].maxa = val;

			d[i].t3 -= k;
			return;
		}

		int mid = l + (r - l) / 2;
		push_down(i, l, r);

		_update_min(i * 2, l, mid, aiml, aimr, val);
		_update_min(i * 2 + 1, mid + 1, r, aiml, aimr, val);
		push_up(i);
	}
public:
	ll getsum(int l, int r)
	{
		return _getsum(1, 1, n, l, r);
	}
	ll getmaxa(int l, int r)
	{
		return _getmaxa(1, 1, n, l, r);
	}
	ll getmaxb(int l, int r)
	{
		return _getmaxb(1, 1, n, l, r);
	}
	void update1(int l, int r, ll val)
	{
		_update1(1, 1, n, l, r, val);//加并挂标记
	}
	void update2(int l, int r, ll val)
	{
		_update2(1, 1, n, l, r, val);//加并挂标记
	}
	void update_min(int l, int r, ll val)
	{
		_update_min(1, 1, n, l, r, val);
	}
	ST(vector<ll>arr)
	{
		a = arr;
		n = a.size() - 1;
		d = vector<node>(4 * n);
		build_tree(1, 1, n);
	}
};

//区间加完,子区间最大值也加
//交汇部分需要再比比

signed main()
{
	ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);

	int n, m;
	cin >> n >> m;
	vector<int>arr(1 + n);
	for (int i = 1; i <= n; i++)
		cin >> arr[i];
	ST demo(arr);
	for (int i = 0; i < m; i++)
	{
		int op, l, r, val;
		cin >> op >> l >> r;
		switch (op)
		{
		case 1:
			cin >> val;
			demo.update1(l, r, val);
			break;
		case 2:
			cin >> val;
			demo.update_min(l, r, val);
			break;
		case 3:
			cout << demo.getsum(l, r) << endl;
			break;
		case 4:
			cout << demo.getmaxa(l, r) << endl;
			break;
		case 5:
			cout << demo.getmaxb(l, r) << endl;
			break;
		}
	}
	return 0;
}

区间乘法可用版:  

简单地整理了下代码,比如函数递归时,l,r可以存入节点node结构体中。递归时,相同的aiml,aimr,val,直接用类成员变量即可,第一次调用时及时修改。

(貌似在O(2)优化下这些修改并没有真正优化。)


因为最大值用了单独的懒标记t3,所以t3需要在区间乘的时候单独乘一下。

以下代码已通过洛谷线段树2

但是线段树3还是有部分超时的,因为线段树3题目没有要求乘法,但是更新时频繁的算乘法标记和取余操作是很耗时间的。具体情况具体看待吧。

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define endl "\n"
#define PII pair<int,int>
#define int long long

const int maxn = 5e5 + 5;
const int minv = -5e18;
int MOD = 19930726;
class ST//segment tree
{
	struct node
	{
		ll val;//区间和
		ll maxa;//区间最大值
		ll seca;//区间次大值
		ll maxb;//区间历史最大值
		ll maxn;//最大值数目 用于最大值修改

		int t1;//加懒标记
		int maxt1;//不是最大值也要统计maxb,也需要最大懒标记
		int t2;//乘懒标记
		int t3;//最大值专属懒标记 VIP
		int maxt3;//期间最大加懒标记

		int l, m,r;

		node(int v = 0) :val(v), maxa(0), seca(-2e9), maxb(0), maxn(1),
			t1(0), maxt1(0), t2(1), t3(0), maxt3(0),l(0),m(0),r(0)
		{}
	};
	int aiml, aimr;
	int val;

	int n = a.size();
	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 = d[i].maxa = d[i].maxb = a[l]%MOD;
			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)%MOD;
		d[i].maxa = max(d[i * 2].maxa, d[i * 2 + 1].maxa);
		d[i].maxb = max(d[i * 2].maxb, d[i * 2 + 1].maxb);
		//不过确实有多个最大值就错了
		if (d[i * 2].maxa == d[i * 2 + 1].maxa)
		{
			d[i].seca = max(d[i * 2].seca, d[i * 2 + 1].seca);
			d[i].maxn = d[i * 2].maxn + d[i * 2 + 1].maxn;
		}
		else if (d[i * 2].maxa > d[i * 2 + 1].maxa)
		{
			d[i].seca = max(d[i * 2].seca, d[i * 2 + 1].maxa);
			d[i].maxn = d[i * 2].maxn;
		}
		else// if (d[i * 2].maxa < d[i * 2 + 1].maxa)
		{
			d[i].seca = max(d[i * 2].maxa, d[i * 2 + 1].seca);
			d[i].maxn = d[i * 2 + 1].maxn;
		}
	}
	void change(int i, int t1, int maxt1, int t2, int t3, int maxt3)
	{
		auto& self = d[i];

		self.val = self.val * t2%MOD;
		self.maxa = self.maxa * t2;
		self.seca = self.seca * t2;
		self.t1 = self.t1*t2%MOD;
		self.t3 = self.t3 * t2 % MOD;
		self.t2 = self.t2*t2%MOD;

		self.val = ((self.val+t1 * (d[i].r - d[i].l + 1 - self.maxn)%MOD)%MOD + t3 * self.maxn)%MOD;
		self.maxb = max(self.maxb, self.maxa + maxt3);
		self.maxa += t3;
		if (self.seca != -2e9)
			self.seca += t1;

		self.maxt1 = max(self.maxt1, self.t1 + maxt1);
		self.t1 = (self.t1+t1)%MOD;
		self.maxt3 = max(self.maxt3, self.t3 + maxt3);
		self.t3 = (self.t3+t3)%MOD;
	}
	void push_down(int i)
	{
		//懒惰
		int t1 = d[i].t1, maxt1 = d[i].maxt1, t2 = d[i].t2, t3 = d[i].t3, maxt3 = d[i].maxt3;
		auto& lchild = d[i * 2], & rchild = d[i * 2 + 1];
		int maxatmp = max(lchild.maxa, rchild.maxa);

		if (lchild.maxa == maxatmp)
			change(i * 2, t1, maxt1, t2, t3, maxt3);
		else
			change(i * 2, t1, maxt1, t2, t1, maxt1);//没专属
		if (rchild.maxa == maxatmp)
			change(i * 2 + 1, t1, maxt1, t2, t3, maxt3);
		else
			change(i * 2 + 1, t1, maxt1, t2, t1, maxt1);

		//复原
		d[i].t1 = d[i].maxt1 = d[i].maxt3 = d[i].t3 = 0;
		d[i].t2 = 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%MOD;

		push_down(i);

		return (_getsum(i * 2) + _getsum(i * 2 + 1))%MOD;
	}
	ll _getmaxa(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].maxa;

		push_down(i);

		return max(_getmaxa(i * 2), _getmaxa(i * 2 + 1));
	}
	ll _getmaxb(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].maxb;

		push_down(i);

		return max(_getmaxb(i * 2), _getmaxb(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))%MOD;
			d[i].maxa = d[i].maxa + val;
			d[i].maxb = max(d[i].maxb, d[i].maxa);
			if (d[i].seca != -2e9)
				d[i].seca += val;

			d[i].t1 = (d[i].t1+val)%MOD;
			d[i].t3 = (d[i].t3+val)%MOD;
			d[i].maxt1 = max(d[i].maxt1, d[i].t1);
			d[i].maxt3 = max(d[i].maxt3, d[i].t3);
			return;
		}

		push_down(i);//因为要向下搜了,所以把当前的懒标记给下面兑现一下

		_update1(i * 2);
		_update1(i * 2 + 1);
		push_up(i);
	}
	void _update2(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)%MOD;
			d[i].t1 = (d[i].t1 * val)%MOD;
			d[i].t3 = (d[i].t3 * val)%MOD;
			d[i].t2 = (d[i].t2 * val)%MOD;
			return;
		}

		push_down(i);

		_update2(i * 2);
		_update2(i * 2 + 1);
		push_up(i);
	}
	void _update_min(int i)
	{
		if (d[i].l > aimr || d[i].r < aiml || d[i].maxa <= val)return;
		if (aiml <= d[i].l && d[i].r <= aimr && d[i].seca < val)
		{
			int k = d[i].maxa - val;

			d[i].val -= d[i].maxn * k;
			d[i].maxa = val;

			d[i].t3 -= k;
			return;
		}

		push_down(i);

		_update_min(i * 2);
		_update_min(i * 2 + 1);
		push_up(i);
	}
public:
	ll getsum(int l, int r)
	{
		aiml = l, aimr = r;
		return _getsum(1);
	}
	ll getmaxa(int l, int r)
	{
		aiml = l, aimr = r;
		return _getmaxa(1);
	}
	ll getmaxb(int l, int r)
	{
		aiml = l, aimr = r;
		return _getmaxb(1);
	}
	void update1(int l, int r, ll val)
	{
		aiml = l, aimr = r;
		this->val = val;
		_update1(1);//加并挂标记
	}
	void update2(int l, int r, ll val)
	{
		aiml = l, aimr = r;
		this->val = val;
		_update2(1);//加并挂标记
	}
	void update_min(int l, int r, ll val)
	{
		aiml = l, aimr = r;
		this->val = val;
		_update_min(1);
	}
	ST(vector<ll>arr)
	{
		a = arr;
		n = a.size() - 1;
		d = vector<node>(4 * n);
		build_tree(1, 1, n);
		a = {};//清空a数组
	}
};

//区间加完,子区间最大值也加
//交汇部分需要再比比

signed main()
{
	ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);

	int n, m, q;
	cin >> n >> m >> q;
	MOD = q;
	vector<ll>arr(n + 1);
	for (int i = 1; i <= n; i++)
		cin >> arr[i];
	ST demo(arr);
	for (int i = 1; i <= m; i++)
	{
		int op;
		cin >> op;
		int x, y, k;
		if (op == 1)
		{
			cin >> x >> y >> k;
			demo.update2(x, y, k);
		}
		else if (op == 2)
		{
			cin >> x >> y >> k;
			demo.update1(x, y, k);
		}
		else //if (op == 3)
		{
			cin >> x >> y;
			cout << demo.getsum(x, y) << endl;
		}

	}
	return 0;
}

终极版:

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define endl "\n"
#define PII pair<int,int>
#define int long long

const int maxn = 5e5 + 5;
const int minv = -5e18;
int MOD = 1e17;
class ST//segment tree
{
	struct node
	{
		ll val;//区间和
		ll maxa;//区间最大值
		ll seca;//区间次大值
		ll maxb;//区间历史最大值
		ll maxn;//最大值数目 用于最大值修改

		int t1;//加懒标记
		int maxt1;//不是最大值也要统计maxb,也需要最大懒标记
		int t2;//乘懒标记
		int t3;//最大值专属懒标记 VIP
		int maxt3;//期间最大加懒标记

		int l, m, r;

		node(int v = 0) :val(v), maxa(0), seca(-2e9), maxb(0), maxn(1),
			t1(0), maxt1(0), t2(1), t3(0), maxt3(0), l(0), m(0), r(0)
		{}
	};
	int aiml, aimr;
	int val;

	int n = a.size();
	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 = d[i].maxa = d[i].maxb = 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) ;
		d[i].maxa = max(d[i * 2].maxa, d[i * 2 + 1].maxa);
		d[i].maxb = max(d[i * 2].maxb, d[i * 2 + 1].maxb);
		//不过确实有多个最大值就错了
		if (d[i * 2].maxa == d[i * 2 + 1].maxa)
		{
			d[i].seca = max(d[i * 2].seca, d[i * 2 + 1].seca);
			d[i].maxn = d[i * 2].maxn + d[i * 2 + 1].maxn;
		}
		else if (d[i * 2].maxa > d[i * 2 + 1].maxa)
		{
			d[i].seca = max(d[i * 2].seca, d[i * 2 + 1].maxa);
			d[i].maxn = d[i * 2].maxn;
		}
		else// if (d[i * 2].maxa < d[i * 2 + 1].maxa)
		{
			d[i].seca = max(d[i * 2].maxa, d[i * 2 + 1].seca);
			d[i].maxn = d[i * 2 + 1].maxn;
		}
	}
	void change(int i, int t1, int maxt1, int t2, int t3, int maxt3)
	{
		auto& self = d[i];

		//self.val = self.val * t2%MOD;
		//self.maxa = self.maxa * t2;
		//self.seca = self.seca * t2;
		//self.t1 = self.t1*t2%MOD;
		//self.t3 = self.t3 * t2 % MOD;
		//self.t2 = self.t2*t2%MOD;

		self.val = ((self.val + t1 * (d[i].r - d[i].l + 1 - self.maxn) )  + t3 * self.maxn) ;
		self.maxb = max(self.maxb, self.maxa + maxt3);
		self.maxa += t3;
		if (self.seca != -2e9)
			self.seca += t1;

		self.maxt1 = max(self.maxt1, self.t1 + maxt1);
		self.t1 = (self.t1 + t1) ;
		self.maxt3 = max(self.maxt3, self.t3 + maxt3);
		self.t3 = (self.t3 + t3) ;
	}
	void push_down(int i)
	{
		//懒惰
		int t1 = d[i].t1, maxt1 = d[i].maxt1, t2 = d[i].t2, t3 = d[i].t3, maxt3 = d[i].maxt3;
		auto& lchild = d[i * 2], & rchild = d[i * 2 + 1];
		int maxatmp = max(lchild.maxa, rchild.maxa);

		if (lchild.maxa == maxatmp)
			change(i * 2, t1, maxt1, t2, t3, maxt3);
		else
			change(i * 2, t1, maxt1, t2, t1, maxt1);//没专属
		if (rchild.maxa == maxatmp)
			change(i * 2 + 1, t1, maxt1, t2, t3, maxt3);
		else
			change(i * 2 + 1, t1, maxt1, t2, t1, maxt1);

		//复原
		d[i].t1 = d[i].maxt1 = d[i].maxt3 = d[i].t3 = 0;
		d[i].t2 = 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 _getmaxa(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].maxa;

		push_down(i);

		return max(_getmaxa(i * 2), _getmaxa(i * 2 + 1));
	}
	ll _getmaxb(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].maxb;

		push_down(i);

		return max(_getmaxb(i * 2), _getmaxb(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));
			d[i].maxa = d[i].maxa + val;
			d[i].maxb = max(d[i].maxb, d[i].maxa);
			if (d[i].seca != -2e9)
				d[i].seca += val;

			d[i].t1 = (d[i].t1 + val);
			d[i].t3 = (d[i].t3 + val);
			d[i].maxt1 = max(d[i].maxt1, d[i].t1);
			d[i].maxt3 = max(d[i].maxt3, d[i].t3);
			return;
		}

		push_down(i);//因为要向下搜了,所以把当前的懒标记给下面兑现一下

		_update1(i * 2);
		_update1(i * 2 + 1);
		push_up(i);
	}
	void _update2(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].t1 = (d[i].t1 * val);
			d[i].t3 = (d[i].t3 * val);
			d[i].t2 = (d[i].t2 * val);
			return;
		}

		push_down(i);

		_update2(i * 2);
		_update2(i * 2 + 1);
		push_up(i);
	}
	void _update_min(int i)
	{
		if (d[i].l > aimr || d[i].r < aiml || d[i].maxa <= val)return;
		if (aiml <= d[i].l && d[i].r <= aimr && d[i].seca < val)
		{
			int k = d[i].maxa - val;

			d[i].val -= d[i].maxn * k;
			d[i].maxa = val;

			d[i].t3 -= k;
			return;
		}

		push_down(i);

		_update_min(i * 2);
		_update_min(i * 2 + 1);
		push_up(i);
	}
public:
	ll getsum(int l, int r)
	{
		aiml = l, aimr = r;
		return _getsum(1);
	}
	ll getmaxa(int l, int r)
	{
		aiml = l, aimr = r;
		return _getmaxa(1);
	}
	ll getmaxb(int l, int r)
	{
		aiml = l, aimr = r;
		return _getmaxb(1);
	}
	void update1(int l, int r, ll val)
	{
		aiml = l, aimr = r;
		this->val = val;
		_update1(1);//加并挂标记
	}
	void update2(int l, int r, ll val)
	{
		aiml = l, aimr = r;
		this->val = val;
		_update2(1);//加并挂标记
	}
	void update_min(int l, int r, ll val)
	{
		aiml = l, aimr = r;
		this->val = val;
		_update_min(1);
	}
	ST(vector<ll>arr)
	{
		a = arr;
		n = a.size() - 1;
		d = vector<node>(4 * n);
		build_tree(1, 1, n);
		a = {};//清空a数组
	}
};

//区间加完,子区间最大值也加
//交汇部分需要再比比

signed main()
{
	ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);

	int n, m;
	cin >> n >> m;
	vector<int>arr(1 + n);
	for (int i = 1; i <= n; i++)
		cin >> arr[i];
	ST demo(arr);
	for (int i = 0; i < m; i++)
	{
		int op, l, r, val;
		cin >> op >> l >> r;
		switch (op)
		{
		case 1:
			cin >> val;
			demo.update1(l, r, val);
			break;
		case 2:
			cin >> val;
			demo.update_min(l, r, val);
			break;
		case 3:
			cout << demo.getsum(l, r) << endl;
			break;
		case 4:
			cout << demo.getmaxa(l, r) << endl;
			break;
		case 5:
			cout << demo.getmaxb(l, r) << endl;
			break;
		}
	}
	return 0;
}

# 线段树框架:


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 = a.size();
	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(_getmaxa(i * 2), _getmaxa(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
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值