【Vijos1083/BZOJ1756】小白逛公园(线段树)

【写在前面】TYC (Little White) 真是太巨啦!

题目:

Vijos1083

分析:

一眼看上去就是线段树啊……

然而当我这种蒟蒻兴高采烈地把线段树模板敲了一半,却发现一个问题:

这子区间最大值的查询咋整啊……

于是经过仔cha细zhao思ti考jie,设计了这样一个线段树结点类型:

struct node  
{  
    int val;  
    int lm;  
    int rm;  
    int mm;  
}tree[2000010];

\(val\)代表这个区间的总和,\(lm\)代表从左边往右搜的最大值,\(rm\)代表从右边往左搜的最大值,\(mm\)代表这个区间的子区间的最大值(就是要求的东西)
于是更新的时候

\(lm\)有两种情况:左子树的\(lm\)或者左子树全部加上右子树\(lm\)\(rm\)同理

\(mm\)有两种情况:左子树/右子树\(mm\)的最大值或者左子树\(rm+\)右子树\(lm\)

    inline void update(int r)  
    {  
        tree[r].val=tree[r*2+1].val+tree[r*2+2].val;  
        tree[r].lm=max(tree[r*2+1].lm,tree[r*2+1].val+tree[r*2+2].lm);  
        tree[r].rm=max(tree[r*2+2].rm,tree[r*2+2].val+tree[r*2+1].rm);  
        tree[r].mm=max(tree[r*2+1].rm+tree[r*2+2].lm,max(tree[r*2+1].mm,tree[r*2+2].mm));  
    }  

然后讨论本题最核心的部分:查询

查询区间只在\(mid\)的左边或右边都很“模板”,但是如果\(mid\)在查询区间中间就很坑,因为要保证求得的区间是连续的

在这里,要查询左右两边,知道左右两边的\(val\)\(lm\)\(rm\)\(mm\),所以\(search\)函数要返回一个\(node\)结构

然后……就用跟上面的\(update\)类似的方法来处理出当前区间的\(val\)\(lm\)\(rm\)\(mm\)(详见代码)

这样\([1,n]\)区间的\(mm\)就是最终结果

代码:

#include<cstdio>
#include<algorithm>
using namespace std;
struct node
{
	int val;
	int lm;
	int rm;
	int mm;
}tree[2000010];
int n,m,in[500010];

inline void update(int r)
{
	tree[r].val=tree[r*2+1].val+tree[r*2+2].val;
	tree[r].lm=max(tree[r*2+1].lm,tree[r*2+1].val+tree[r*2+2].lm);
	tree[r].rm=max(tree[r*2+2].rm,tree[r*2+2].val+tree[r*2+1].rm);
	tree[r].mm=max(tree[r*2+1].rm+tree[r*2+2].lm,max(tree[r*2+1].mm,tree[r*2+2].mm));
}
void build(int r,int lt,int rt)
{
	if(lt>rt)return;
	if(lt==rt)
	{
		tree[r].val=tree[r].lm=tree[r].rm=tree[r].mm=in[lt];
		return;
	}
	int mid=(lt+rt)/2;
	build(r*2+1,lt,mid);
	build(r*2+2,mid+1,rt);
	update(r);
}
void change(int r,int lt,int rt,int p,int x)
{
	if(lt>rt||lt>p||rt<p)return;
	if(lt==rt)
	{
		tree[r].val=tree[r].lm=tree[r].rm=tree[r].mm=x;
		return;
	}
	int mid=(lt+rt)/2;
	if(p<=mid)change(r*2+1,lt,mid,p,x);
	else change(r*2+2,mid+1,rt,p,x);
	update(r);
}

node search(int r,int lt,int rt,int ls,int rs)
{
	if(lt>rt||lt>rs||rt<ls)return (node){-0x3f3f3f3f,0,0};
	if(lt>=ls&&rt<=rs)return tree[r];
	int mid=(lt+rt)/2;
	if(rs<=mid)return search(r*2+1,lt,mid,ls,rs);
	else if(ls>mid)return search(r*2+2,mid+1,rt,ls,rs);
	else
	{
		node ln,rn,ans;
		ln=search(r*2+1,lt,mid,ls,rs);
		rn=search(r*2+2,mid+1,rt,ls,rs);
		ans.val=ln.val+rn.val;
		ans.lm=max(ln.lm,ln.val+rn.lm);
		ans.rm=max(rn.rm,rn.val+ln.rm);
		ans.mm=max(ln.rm+rn.lm,max(ln.mm,rn.mm));
		return ans;
	}
}
int main(void)
{
	scanf("%d%d",&n,&m);
	for(int i=1;i<=n;i++)
		scanf("%d",in+i);
	build(0,1,n);
	while(m--)
	{
		int a,b,c;
		scanf("%d%d%d",&a,&b,&c);
		if(a==1)
		{
			node ans=search(0,1,n,min(b,c),max(b,c));
			printf("%d\n",ans.mm);
		}
		else
			change(0,1,n,b,c);
	}
	return 0;
} 
posted @ 2018-04-18 18:39  Inspector_Javert  阅读(215)  评论(0编辑  收藏  举报