BZOJ 1756: Vijos1083 小白逛公园  (线段树维护单点修改区间查询最大子段和)

1756: Vijos1083 小白逛公园

Time Limit: 10 Sec  Memory Limit: 64 MB Submit: 1078  Solved: 353 [Submit][Status][Discuss]

Description

小新经常陪小白去公园玩,也就是所谓的遛狗啦…在小新家附近有一条“公园路”,路的一边从南到北依次排着n个公园,小白早就看花了眼,自己也不清楚该去哪些公园玩了。   一开始,小白就根据公园的风景给每个公园打了分-.-。小新为了省事,每次遛狗的时候都会事先规定一个范围,小白只可以选择第a个和第b个公园之间(包括a、b两个公园)选择连续的一些公园玩。小白当然希望选出的公园的分数总和尽量高咯。同时,由于一些公园的景观会有所改变,所以,小白的打分也可能会有一些变化。   那么,就请你来帮小白选择公园吧。

Input

第一行,两个整数N和M,分别表示表示公园的数量和操作(遛狗或者改变打分)总数。 接下来N行,每行一个整数,依次给出小白 开始时对公园的打分。 接下来M行,每行三个整数。第一个整数K,1或2。K=1表示,小新要带小白出去玩,接下来的两个整数a和b给出了选择公园的范围(1≤a,b≤N);K=2表示,小白改变了对某个公园的打分,接下来的两个整数p和s,表示小白对第p个公园的打分变成了s(1≤p≤N)。 其中,1≤N≤500 000,1≤M≤100 000,所有打分都是绝对值不超过1000的整数。

Output

小白每出去玩一次,都对应输出一行,只包含一个整数,表示小白可以选出的公园得分和的最大值。

Sample Input

5 3 1 2 -3 4 5 1 2 3 2 2 -1 1 2 3

Sample Output

2 -1

题意:中文题面,不多说。

思路:关于维护最大子段和的问题,做法同

hitoj2687题解

但是和上面这道题不同的是,每次询问的是某个区间的最大字段和,而不是整个区间的最大子段和。

我们的做法是,将查询的区间拆成若干个区间,然后按照pushup中的方法合并。

一个技巧是query的时候返回一个结构体,这样会比较好写。

/* ***********************************************
Author :111qqz
Created Time :Fri 16 Sep 2016 03:15:50 AM CST
File Name :code/bzoj/1756.cpp
************************************************ */
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <vector>
#include <queue>
#include <set>
#include <map>
#include <string>
#include <cmath>
#include <cstdlib>
#include <ctime>
#define fst first
#define sec second
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
#define ms(a,x) memset(a,x,sizeof(a))
typedef long long LL;
#define pi pair < int ,int >
#define MP make_pair
using namespace std;
const double eps = 1E-8;
const int dx4[4]={1,0,0,-1};
const int dy4[4]={0,-1,1,0};
const int inf = 0x3f3f3f3f;
const int N=5E5+7;
int n,m;
int a[N];
struct Tree
{
    int sum;
    int mxl;
    int mxr;
    int mx;
}tree[N<<2];
void PushUp(int rt)
{
    tree[rt].sum = tree[rt<<1].sum+tree[rt<<1|1].sum;
    if (tree[rt<<1].mxr>0&&tree[rt<<1|1].mxl>0)
	tree[rt].mx = tree[rt<<1].mxr+tree[rt<<1|1].mxl;
    else tree[rt].mx = max(tree[rt<<1].mxr,tree[rt<<1|1].mxl);
    tree[rt].mx = max(tree[rt].mx,max(tree[rt<<1].mx,tree[rt<<1|1].mx));
    tree[rt].mxl=max(tree[rt<<1].mxl,tree[rt<<1].sum+tree[rt<<1|1].mxl);
    tree[rt].mxr=max(tree[rt<<1|1].mxr,tree[rt<<1|1].sum+tree[rt<<1].mxr);
}
void build(int l,int r,int rt)
{
 //   cout<<"l:"<<l<<" r:"<<r<< " rt:"<<rt<<endl;
    if (l==r)
    {
	int tmp;
	scanf("%d",&tmp);
//	cout<<"tmp:"<<tmp<<endl;
	tree[rt].mx = tree[rt].mxl = tree[rt].mxr = tree[rt].sum = tmp;
	return ;
    }
    int m = (l+r)>>1;
    build(lson);
    build(rson);
    PushUp(rt);
}
void update( int p,int sc,int l,int r,int rt)
{
    if (l==r)
    {
	tree[rt].mx = tree[rt].mxl = tree[rt].mxr = tree[rt].sum = sc;
	return ;
    }
    int m = (l+r)>>1;
    if (p<=m) update(p,sc,lson);
    else update(p,sc,rson);
    PushUp(rt);
}
Tree query(int L,int R,int l,int r,int rt)
{
    if (L<=l&&r<=R) return tree[rt];
    int m = (l+r)>>1;
    if (L<=m&&R>=m+1)
    {
	Tree root,ltree,rtree;
	ltree=query(L,R,lson);
	rtree=query(L,R,rson);
	root.sum = ltree.sum + rtree.sum;
	if (ltree.mxr>0&&rtree.mxl>0)
	    root.mx = ltree.mxr + rtree.mxl;
	else root.mx = max(ltree.mxr,rtree.mxl);
	root.mx = max(root.mx,max(ltree.mx,rtree.mx));
	root.mxl = max(ltree.mxl,rtree.mxl+ltree.sum);
	root.mxr = max(rtree.mxr,ltree.mxr+rtree.sum);
	return root;
    }
    else
    if (L<=m) return query(L,R,lson);
    else   return query(L,R,rson);
}
int main()
{
	#ifndef  ONLINE_JUDGE 
	freopen("code/in.txt","r",stdin);
  #endif
	scanf("%d%d",&n,&m);
	build(1,n,1);
	while (m--)
	{
	    int opt;
	    scanf("%d",&opt);
	    if (opt==1)
	    {
		int a,b;
		scanf("%d%d",&a,&b);
		if (a>b) swap(a,b);
		int ans = query(a,b,1,n,1).mx;
		printf("%d\n",ans);
	    }else
	    {
		int p,x;
		scanf("%d%d",&p,&x);
		update(p,x,1,n,1);
	    }
	}
  #ifndef ONLINE_JUDGE  
  fclose(stdin);
  #endif
    return 0;
}