题解【SP1716】GSS3 - Can you answer these queries III

题目描述

You are given a sequence \(A\) of \(N (N <= 50000)\) integers between \(-10000\) and \(10000\). On this sequence you have to apply \(M (M <= 50000)\) operations:

modify the \(i\)-th element in the sequence or for given \(x\) \(y\) print \(max\{A_i + A_{i+1} + .. + A_j\) \(|\) \(x<=i<=j<=y \}\).

输入输出格式

输入格式

The first line of input contains an integer \(N\).

The following line contains \(N\) integers, representing the sequence \(A_{1}..A_{N}\).

The third line contains an integer \(M\). The next \(M\) lines contain the operations in following form:

0 x y: modify \(A_x\) into \(y\) \((|y|<=10000)\).

1 x y: print \(max\{A_i + A_{i+1} + .. + A_j\) \(|\) \(x<=i<=j<=y\}\).

输出格式

For each query, print an integer as the problem required.

输入输出样例

输入样例#1

4
1 2 3 4
4
1 1 3
0 3 -3
1 2 4
1 3 3

输出样例#1

6
4
-3

题意翻译

\(n\) 个数,\(q\) 次操作

操作0 x y\(A_x\) 修改为\(y\)

操作1 l r询问区间\([l, r]\)的最大子段和

题解

这题就是GSS1的带修改版本,建议先看一看我的题解,了解不带修改的版本怎么写。

本题的代码基于我GSS1的题解,一些注释也可以在那里看到。

这里讲一讲怎么修改:

与线段树相似,如果当前已经访问到了叶子节点,就直接将这个节点的所有参数都设为要修改的值即可,否则就递归左子树或右子树。最后记得上传节点!

下面给出\(AC\)代码:

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <cctype>

using namespace std;

inline int gi()
{
    int f = 1, x = 0; char c = getchar();
    while (c < '0' || c > '9') { if (c == '-') f = -1; c = getchar();}
    while (c >= '0' && c <= '9') { x = x * 10 + c - '0'; c = getchar();}
    return f * x;
}

int n, m;
struct Node
{
	int sum, lans, rans, ans;
} t[50005 << 2];

inline void pushup(int x)
{
	t[x].sum = t[x << 1].sum + t[(x << 1) | 1].sum;
	t[x].lans = max(t[x << 1].lans, t[x << 1].sum + t[(x << 1) | 1].lans);
	t[x].rans = max(t[(x << 1) | 1].rans, t[(x << 1) | 1].sum + t[x << 1].rans);
	t[x].ans = max(max(t[x << 1].ans, t[(x << 1) | 1].ans), t[x << 1].rans + t[(x << 1) | 1].lans);
}

void bulid(int s, int o, int p)
{
	if (s == o)
	{
		t[p].sum = t[p].lans = t[p].rans = t[p].ans = gi();
		return;
	}
	int mid = (s + o) >> 1;
	bulid(s, mid, p << 1);
	bulid(mid + 1, o, (p << 1) | 1);
	pushup(p);
}

void modify(int l, int r, int s, int o, int p)//修改操作
{
	if (s == o)//已经是叶子节点了
	{
		t[p].ans = t[p].lans = t[p].rans = t[p].sum = r;//就更新它的所有参数
		return;
	}
	int mid = (s + o) >> 1;//找中点
	if (l <= mid) modify(l, r, s, mid, p << 1);//点在中点左边就递归左子树
	else modify(l, r, mid + 1, o, (p << 1) | 1);//否则递归右子树
	pushup(p);//上传节点
}

Node getans(int l, int r, int s, int o, int p)
{
	if (l <= s && r >= o)
	{
		return t[p];
	}
	int mid = (s + o) >> 1;
	if (l > mid) return getans(l, r, mid + 1, o, (p << 1) | 1);
	if (r <= mid) return getans(l, r, s, mid, p << 1);
	else 
	{
		Node ans, a, b;
		a = getans(l, r, s, mid, p << 1), b = getans(l, r, mid + 1, o, (p << 1) | 1);
		ans.sum = a.sum + b.sum;
		ans.ans = max(max(a.ans, a.rans + b.lans), b.ans);
		ans.lans = max(a.lans, a.sum + b.lans);
		ans.rans = max(b.rans, b.sum + a.rans);
		return ans;
	}
}

int main()
{
	n = gi();
	bulid(1, n, 1);
	m = gi();
	for (int i = 1; i <= m; i++)
	{
		int fl = gi(), x = gi(), y = gi();
		if (fl == 1) printf("%d\n", getans(x, y, 1, n, 1).ans);//如果是要求答案就输出答案
		else modify(x, y, 1, n, 1);//否则就进行修改
	}
	return 0;
}
posted @ 2019-07-04 10:59  csxsi  阅读(159)  评论(0编辑  收藏  举报