结构体线段树又双叒叕求调...
查看原帖
结构体线段树又双叒叕求调...
759274
Stevehim楼主2023/1/19 20:09
#include <cstdio>
#include <cstring>
#include <iostream>
#include <cmath>
#include <algorithm>
#include <string>
#define maxn 1000010
using namespace std;
typedef long long ll; //开ll
#define inf -100000000
/*
默写结构体线段树
范围为模板1-2
*/
//本题为两个标签问题


struct node {
	int l;
	int r;
	ll val;
	ll add = 0; //加法标记 //开long long !!!! 十年OI一场空,不开longlong 见祖宗
	ll add2 = inf;//修改标记
	ll ma = 0;
} a[maxn];

int num[maxn]; //存放值的数组

void build(int p, int l, int r) {
	a[p].l = l;
	a[p].r = r;
	if (l == r) {
		a[p].val = num[l];
		return;
	}
	int mid = (l + r) / 2;
	build(p * 2, l, mid); //建立左子树
	build(p * 2 + 1, mid + 1, r); //建立右子树
	a[p].val = a[p * 2].val + a[p * 2 + 1].val;
	a[p].ma = max(a[p * 2].val, a[p * 2 + 1].val); //更新最大值
	return;
}

/*
spread函数的标注:
1.区间+1的原因:假设 1 2 3 4 5,我的l为1,r为5,那么我用r - l为4,会忽略掉一个端点
(其实根节点设为0有可能不会出错但是根节点设为零p*2会出错)
*/
void spread(int p) { //下传操作
	if (a[p].add2 != inf) { //检测赋值标记是否存在
		a[p].add2 += a[p].add; //加上修改标记,如果没有也没关系反正是0
		a[p * 2].val = (a[p * 2].r - a[p * 2 ].l + 1) * a[p].add2; //更新
		a[p * 2 + 1].val = (a[p * 2 + 1].r - a[p * 2 + 1].l + 1) * a[p].add2; //更新
		a[p * 2].add2 = a[p].add2; //更新标记
		a[p * 2].add = 0; //因为相当于同时传了俩标记,这块就放成0防止额外加
		a[p * 2 + 1].add = 0; //参见上方
		a[p].add = 0;
		a[p].add2 = inf;
	} else { //没有加赋值标记
		a[p * 2].val += (a[p * 2].r - a[p * 2 ].l + 1) * a[p].add;
		a[p * 2 + 1].val += (a[p * 2 + 1].r - a[p * 2 + 1].l + 1) * a[p].add; //注意是添加
		a[p * 2].add += a[p].add;
		a[p * 2 + 1].add += a[p].add; //同样注意是添加,而不是像刚刚的直接等
		a[p].add = 0;
	}
}

void change1(int p, int l, int r, int z) {
	if (l <= a[p].l && r >= a[p].r) { //覆盖了
		a[p].add += z;
		a[p].val += (ll)z * (a[p].r - a[p].l + 1); //更新最大值
		a[p].ma = max(a[p * 2].val, a[p * 2 + 1].val); //更新最大值
		return;
	}
	spread(p);
	int mid = (a[p].l + a[p].r) / 2; //注意:不是 l 与 r !!!
	if (l <= mid) {
		change1(p * 2, l, r, z);
	}
	if (r > mid) {
		change1(p * 2 + 1, l, r, z);
	}
	a[p].val = a[p * 2].val + a[p * 2 + 1].val; //加上值
	a[p].ma = max(a[p * 2].val, a[p * 2 + 1].val); //更新最大值
}

void change2(int p, int l, int r, int z) { //针对change1微调亿下就行
	if (l <= a[p].l && r >= a[p].r) { //覆盖了
		a[p].add2 = z; //直接执行
		a[p].val = (ll)(a[p].r - a[p].l + 1) * z; //更新值
		a[p].ma = max(a[p * 2].val, a[p * 2 + 1].val); //更新最大值
		return;
	}
	spread(p);
	int mid = (a[p].l + a[p].r) / 2;
	if (l <= mid) {
		change2(p * 2, l, r, z);
	}
	if (r > mid) {
		change2(p * 2 + 1, l, r, z);
	}
	a[p].val = a[p * 2].val + a[p * 2 + 1].val; //加上值
	a[p].ma = max(a[p * 2].val, a[p * 2 + 1].val); //更新最大值
}

ll ask(int p, int l, int r) { //稍 作 修 改
	if (l <= a[p].l && r >= a[p].r) {
		return a[p].ma;
	}
	spread(p);
	ll ans1, ans2;
	int mid = (a[p].l + a[p].r) / 2;
	if (l <= mid) {
		ans1 = ask(p * 2, l, r); //注意是等于,因为要最大值
	}
	if (r > mid) {
		ans2 = ask(p * 2 + 1, l, r);
	}
	return max(ans1, ans2);
}
int n, q;

int main() {
	//以下为线段树1代码
	cin >> n >> q;
	for (int i = 1; i <= n; i++) {
		cin >> num[i];
	}
	build(1, 1, n); //建树
	int op, l, r, x;
	for (int i = 1; i <= q; i++) {
		cin >> op;
		switch (op) {
			case 1: {
				cin >> l >> r >> x;
				change2(1, l, r, x);
				break;
			}
			case 2: {
				cin >> l >> r >> x;
				change1(1, l, r, x);
				break;
			}
			case 3: {
				cin >> l >> r;
				cout << ask(1, l, r) << endl;
				break;
			}
		}
	}
	return 0;
}

2023/1/19 20:09
加载中...