[Acwing245]你能回答这个问题吗

一、题目

Acwing245
image
image

二、思路

用线段树求最大区间连续子段和
对于ans = max{左边区间的最大子段和,右边区间的最大子段和,跨越两个区间的最大子段和}
因此在写结构体时,节点应包含
sum:当前区间和
lmax:从左开始的最大子段和
rmax:从右开始的最大子段和
dat:整个区间的最大子段和

如果当前区间被要查询区间完全包含,返回当前区间的信息
如果要查询的区间只在当前区间的左区间,向左区间查询
如果要查询的区间只在当前区间的右区间,向右区间查询
其他情况,像pushup那样合并左右区间的查询结果,并返回

三、代码

#include<bits/stdc++.h>
using namespace std;
const int N = 5e5 + 10;
typedef long long ll;
#define u1 (u << 1)
#define u2 (u << 1 | 1)
struct Node{
	int l, r;
	int lmax, rmax;
	int sum, dat;
}tr[N * 4];

void pushup(int u){
	tr[u].sum = tr[u1].sum + tr[u2].sum;
	tr[u].dat = max(max(tr[u1].dat, tr[u2].dat), tr[u1].rmax + tr[u2].lmax);
	tr[u].lmax = max(tr[u1].lmax, tr[u1].sum + tr[u2].lmax);
	tr[u].rmax = max(tr[u2].rmax, tr[u2].sum + tr[u1].rmax);
}

void build(int u, int l, int r){
	tr[u].l = l;
	tr[u].r = r;
	if(l == r) {
		int p;
		cin >> p;
		tr[u] = {l, r, p, p, p, p};
		return;
	}
	int mid = l + r >> 1;
	build(u1, l, mid), build(u2, mid + 1, r);
	pushup(u);
}

Node query(int u, int l, int r){
	if(tr[u].l >= l && tr[u].r <= r) return tr[u];
	int mid = tr[u].l + tr[u].r >> 1;
	if(r <= mid) return query(u1, l, r);
	else if(l > mid) return query(u2, l, r);
	else {
		Node t1 = query(u1, l, mid), t2 = query(u2, mid + 1, r), t3;
		t3.l = l, t3.r = r;
		t3.sum = t1.sum + t2.sum;
		t3.dat = max(max(t1.dat, t2.dat), t1.rmax + t2.lmax);
		t3.lmax = max(t1.lmax, t2.lmax + t1.sum);
		t3.rmax = max(t2.rmax, t1.rmax + t2.sum);
		return t3;
	}
}

void modify(int u, int x, int y){
	if(tr[u].l == x && tr[u].r == x){
		tr[u] = {x, x, y, y, y, y};
		return;
	}
	int mid = tr[u].l + tr[u].r >> 1;
	if(x <= mid) modify(u1, x, y);
	if(x > mid) modify(u2, x, y);
	pushup(u);
}

int main(){
	int n, m;
	cin >> n >> m;
	build(1, 1, n);
	int x, y;
	while(m --){
		int op;
		cin >> op;
		if(op == 1) {
			cin >> x >> y;
			if(x > y) swap(x, y);
			cout << query(1, x, y).dat << endl;
		}
		else {
			cin >> x >> y;
			modify(1, x, y);
		}
	}
	
	
	return 0;
}
posted @ 2021-10-15 21:42  行舟C  阅读(50)  评论(0)    收藏  举报