luogu P4513ybtoj线段树课堂过关例题3小白逛公园

Posted SSL_ZZL

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了luogu P4513ybtoj线段树课堂过关例题3小白逛公园相关的知识,希望对你有一定的参考价值。

【例题3】小白逛公园


Link

luogu P4513 小白逛公园
ybtoj【线段树课堂过关】【例题3】小白逛公园
题面//因为不知道侵不侵权所以就是题面是私密的,有账号的直接看转送门就可了


题目大意

给你一个序列,要维护两个操作。
单点修改和在一个区间中找权值最大的子区间的权值。


解题思路

第一次学习这种模板(也有可能不是第一次😅)

找一个最大的区间,可以想到用 左子树的最大后缀 + 右子树的最大前缀 拼在一起
每个节点多加上三个附加值—— l s u m , r s u m , s u m lsum,rsum,sum lsum,rsum,sum,就是左子树的最大后缀, 右子树的最大前缀,最大区间
为了保证最大后缀和最大前缀能拼在一起,这两个缀必须加上对方…
t r e e [ r o o t ∗ 2 ] . r s u m + t r e e [ r o o t ∗ 2 + 1 ] . s tree[root * 2].rsum + tree[root * 2 + 1].s tree[root2].rsum+tree[root2+1].s=>最大后缀
t r e e [ r o o t ∗ 2 + 1 ] . l s u m + t r e e [ r o o t ∗ 2 ] . s tree[root * 2 + 1].lsum + tree[root * 2].s tree[root2+1].lsum+tree[root2].s=>最大前缀


Code

#include <iostream>
#include <cstdio>
#define ll long long

using namespace std;

struct DT{
	ll s, lsum, rsum, sum;
}tree[4001000];
int n, m, a[500100], c, x, y;

void up(int root) {
	tree[root].s = tree[root * 2].s + tree[root * 2 + 1].s;
	tree[root].lsum = max(tree[root * 2].lsum, tree[root * 2].s + tree[root * 2 + 1].lsum);
	tree[root].rsum = max(tree[root * 2 + 1].rsum, tree[root * 2 + 1].s + tree[root * 2].rsum);
	tree[root].sum = max(max(tree[root * 2].sum, tree[root * 2 + 1].sum), tree[root * 2].rsum + tree[root * 2 + 1].lsum);
}

void build(int root, int l, int r) {
	if(l == r) {
		tree[root].s = a[l];
		tree[root].lsum = tree[root].rsum = tree[root].sum = a[l];
		return;
	}
	int mid = (l + r) / 2;
	build(root * 2, l, mid);
	build(root * 2 + 1, mid + 1, r);
	up(root);
}

DT find(int root, int l, int r, int x, int y) {
	if(x <= l && r <= y)
		return tree[root];
	int mid = (l + r) / 2;
	
	//目标区间在一边
	if(y <= mid) return find(root * 2, l, mid, x, y);
	if(x > mid) return find(root *2 + 1, mid + 1, r, x, y);
	
	//目标区间分两半
	DT now;
	DT now1 = find(root * 2, l, mid, x, y);
	DT now2 = find(root * 2 + 1, mid + 1, r, x, y);
	
	now.s = now1.s + now2.s;
	now.lsum = max(now1.lsum, now1.s + now2.lsum);
	now.rsum = max(now2.s + now1.rsum, now2.rsum);
	now.sum = max(max(now1.sum, now2.sum), now1.rsum + now2.lsum);
	return now;
}

void change(int root, int l, int r, int x, int y) {
	if(l == r) {
		tree[root].s = y;
		tree[root].lsum = tree[root].rsum = tree[root].sum = y;
		return;
	}
	int mid = (l + r) / 2;
	if(x <= mid) 
		change(root * 2, l, mid, x, y);
	else 
		change(root * 2 + 1, mid + 1, r, x, y);
	up(root);
}

int main() {
	scanf("%d %d", &n, &m);
	for(int i = 1; i <= n; i++)
		scanf("%d", &a[i]);
	build(1, 1, n);
	for(int i = 1; i <= m; i++) {
		scanf("%d %d %d", &c, &x, &y);
		if(c == 1) {
			if(x > y) swap(x, y);
			printf("%lld\\n", find(1, 1, n, x, y).sum);
		}else change(1, 1, n, x, y);
	}
}

以上是关于luogu P4513ybtoj线段树课堂过关例题3小白逛公园的主要内容,如果未能解决你的问题,请参考以下文章

ybtoj线段树课堂过关例题1求区间和

ybtoj 单调队列课堂过关luogu P1886例题1滑动窗口

luogu UVA10559 ybtoj 区间DP课堂过关 例题3消除木块 & 方块消除 Blocks

luogu P4170ybtoj 区间DP课堂过关 例题2木板涂色 & [CQOI2007]涂色

luogu P1352ybtoj 树形DP课堂过关 例题1树上求和 & 没有上司的舞会

luogu P1880ybtoj 区间DP课堂过关 例题1石子合并 & [NOI1995] 石子合并