AcWing 245. 你能回答这些问题吗

文章目录

心得

题意很简单就不过多叙述,这个题对个人最大的启发就是,在我们写线段树时,设计变量时一定要考虑清楚。
当前设置的变量能不能把答案算出,如果不能我们就要再定义额外的变量,然后再看额外的变量能不能计算出来,不能再开变量,直到所有的都能够被计算出来为止。
以本题举例:我们要算[L, R]区间最大的字段连续的和,如果我们只是设置一个表达字段和的变量tmax,如果当这段区间出现跨区间的现象我们就凭这一个变量是无法算出答案的,所以我们在来设置每个区间的前缀最大值,和后缀最大值,但是我们要计算父节点的前缀最大值和后缀最大值时,我们又将面临一个跨区间的问题,所以我们再对于没一个区间设置一个区间和的变量,那么我么所设置的所有变量都将可以得到计算得出。

代码

#include<bits/stdc++.h>

#define IOS ios::sync_with_stdio(false);cin.tie(nullptr)
#define int long long
#define endl "\n"
#define xx first
#define yy second

using namespace std;

typedef pair<int, int> PII;

const int N = 5e5+10, INF = 1e9 + 10;

int n, m;
int arr[N];

struct node
{
	int l, r;
	
	int sum;
	int lmax, rmax, tmax;
}tr[N*4];

void pushup (node &u, node &l, node &r)
{
	u.sum = l.sum+r.sum;
	u.lmax =  max(l.lmax, l.sum+r.lmax);
	u.rmax = max(r.rmax, r.sum+l.rmax);
	u.tmax = max(max(l.tmax, r.tmax), l.rmax+r.lmax);
}

void pushup(int u)
{
	pushup(tr[u], tr[u<<1], tr[u << 1 | 1]);
}

void build(int u, int l, int r)
{
	if(l == r) tr[u] = {l, r, arr[r], arr[r], arr[r], arr[r]};
	else
	{
		tr[u] = {l,r};
		int mid = l+r >> 1;
		build(u << 1, l, mid), build(u << 1 | 1, mid+1, r);
		pushup(u);
	}
}

void modify(int u, int x, int v)
{
	if(tr[u].l == x && tr[u].r == x) tr[u] = {x, x, v, v, v, v};
	else
	{
		int mid = tr[u].l + tr[u].r >> 1;
		if(x <= mid) modify(u << 1, x, v);
		else modify(u << 1 | 1, x, v);
		pushup(u);
	}
}

node query(int u, int l, int r)
{
	if(tr[u].l >= l && tr[u].r <= r) return tr[u];
	else
	{
		int mid = tr[u].l + tr[u].r >> 1;
		if(l > mid) return query(u << 1 | 1, l, r);
		else if(r <= mid)return query(u << 1, l, r);
		else
		{
			auto left = query(u << 1, l, r);
			auto right = query(u << 1 | 1, l, r);
			node tree;
			pushup(tree, left, right);
			return tree;
		}
	}
}

signed main()
{
	IOS;
	cin >> n >> m;
	for(int i = 1; i <= n; i ++) cin >> arr[i];

	build(1, 1, n);

	while(m--)
	{
		int op, l, r;
		cin >> op >> l >> r;
		
		if(op == 1)
		{
			if(l > r) swap(l, r);
			cout << query(1, l, r).tmax << endl;
		}
		else modify(1, l, r);
	}
	return 0;

}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值