zoukankan      html  css  js  c++  java
  • 【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
    ",ans.mm);
    		}
    		else
    			change(0,1,n,b,c);
    	}
    	return 0;
    } 
    
  • 相关阅读:
    Luogu P1396 营救
    Luogu P1339 热浪Heat Wave
    哈夫曼树学习笔记
    题解 CF1372C
    题解 CF 1372 B
    题解 CF 1372A
    题解 UVA1193 Radar Installation
    题解 洛谷 P2287 [USACO07NOV]Sunscreen G
    洛谷 P1080 国王游戏 题解
    牛客练习赛 66C公因子 题解
  • 原文地址:https://www.cnblogs.com/zyt1253679098/p/8876853.html
Copyright © 2011-2022 走看看