UVALive 3938 and UESTC 844

UESTC 844 and UVALive 3938
Problem
  给一个长度为N的数列A,进行M次操作,操作分两种;一,修改数列位置x的值为val;二,查询数列[L,R]区间中的最大连续子列,输出数值大小和起末位置。

More
对于UESTC 844,操作二中,不需要输出起末位置;对于UVALive 3938,没有操作一,但需要输出起末位置,当有多个答案区间时,输出左端点最小的,左端点一致时,输出右端点最小的。两题基本方法一样。

Limits(UESTC 844)
Time Limit(ms): 1000
Memory Limit(MB): 65
N,M :[1, 10^5]
x: [1, N]
Ai: [-10^4, 10^4]
v: [-10^4, 10^4]

Limits(UVALive 3938)
Time Limit(ms): 3000
Memory Limit(MB): No Limit
N,M: [1, 5*10^5]
x: [1, N]
Ai: [-10^9, 10^9]
v: [-10^9, 10^9]

Solution(UESTC 844)
  线段树每个结点有 l 和 r,意为该结点表示的区间的左右端点;再设置4个域,前缀最大值(leftmax),后缀最大值(rightmax),最大值(max),总和(sum)。前缀最大值表示A[l]A[l+1]A[l+2]......A[k](l=<k<=r)中的最大总和,后缀最大值类似,最大值意为该结点表示的区间的最大总和,总和意为该结点表示的区间的总和。
  对于叶子结点,leftmax=rightmax=max=sumA[l];对于非叶子结点,其4个域由左右孩子来维护。前缀最大值为左孩子的前缀最大值和左孩子的总和+右孩子的前缀最大值里最大的一个;后缀最大值为右孩子的后缀最大值和右孩子的总和+左孩子的后缀最大值里最大的一个;总和为两个孩子的总和之和;最大值取以下5个值里的最大一个:一,左孩子的最大值;二,右孩子的最大值;三,当前结点的前缀最大值;四,当前结点的后缀最大值;五,左孩子的后缀最大值+右孩子的前缀最大值。

Solution(UVALive 3938)
  在Solution(UESTC 844)基础上,再设置3个域,前缀最大值区间,后缀最大值区间,最大值区间,分别表示三个最大值对应的区间。在维护最大值的同时,维护答案区间。

More
  在查询操作中,若当前结点区间等于查询区间,则维护后返回;若当前结点的左孩子或右孩子包括了(但不等于)待查询区间,则继续往左孩子或者右孩子查询;若待查询区间一部分属于左孩子,一部分属于右孩子,则需用Solution中的方法,待查询区间的域值来自左孩子和右孩子的待查询区间。
  这两题写起来比较麻烦,尤其是UVALive 3938,需要谨慎拍码。不小心就可能失之毫厘,差之千里。

Complexity
Time Complexity: O(M*logN)
Memory Complexity: O(4*N)

Source
UESTC 844
UVALive 3938

Code
UESTC 844
UVALive 3938 From My Github


你可能感兴趣的:(线段树,单点更新,区间查询,最大连续子列)