• bzoj1756 Vijos1083 小白逛公园


    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

    有一点坑的线段树……你需要特殊的写代码技巧

    每个线段树节点要保存几个数据:lm从左节点往右能取到的最大值,rm从右节点往左能取到的最大值。ans保存当前区间任取一段的最大值

    因为是单点更新,所以连lazy tag也不需要,精华在于询问和标记上传的函数


    上传标记的时候要更新好多东西:

    区间和tot:最简单,左边加右边

    lm:可以取左边的一整段加右边的lm,或者只取左边的lm。lm=max(左边的tot+右边的lm,左边的lm)

    rm:可以取右边的一整段加左边的rm,或者只取右边的rm。rm=max(右边的tot+左边的rm,右边的rm)

    ans:可以取更新完的当前的lm、rm,或者取左边的rm加右边的lm


    然后询问的时候函数的返回值要是一个线段树的节点而不只是一个数据答案

    因为从左右转移的时候,你不知道这个答案是从左边的rm还是ans转移而来,右边也是

    具体来说,如果左边从rm转移而来,那么它可以和右边的lm合并,而ans不能保证会“紧贴“在区间的右边,就不能和右边的lm合并

    所以要返回一个线段树的节点,然后一切都简单了

    #include<cstdio>
    inline int read()
    {
        int x=0,f=1;char ch=getchar();
        while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
        while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
        return x*f;
    }
    inline void swap(int &a,int &b){int t=a;a=b;b=t;}
    inline int max(int a,int b){if (a>b)return a;else return b;}
    struct trees{int l,r,ls,rs,lm,rm,ans,tot;}tree[2000001];
    int n,m,a[500001],treesize;
    inline void update(int k)
    {
    	int ll=tree[k].ls,rr=tree[k].rs;
    	tree[k].tot=tree[ll].tot+tree[rr].tot;
    	tree[k].lm=max(tree[ll].lm,tree[ll].tot+tree[rr].lm);
    	tree[k].rm=max(tree[rr].rm,tree[rr].tot+tree[ll].rm);
    	tree[k].ans=max(max(tree[ll].ans,tree[rr].ans),tree[ll].rm+tree[rr].lm);
    }
    inline void buildtree(int l,int r)
    {
    	if (l>r) return;
    	int now=++treesize;
    	tree[now].l=l;tree[now].r=r;
    	if (l==r)
    	{
    		tree[now].tot=tree[now].lm=tree[now].rm=tree[now].ans=a[l];
    		return;
    	}
    	int mid=(l+r)>>1;
    	tree[now].ls=treesize+1;
    	buildtree(l,mid);
    	tree[now].rs=treesize+1;
    	buildtree(mid+1,r);
    	update(now);
    }
    inline trees ask(int k,int l,int r)
    {
    	int x=tree[k].l,y=tree[k].r;
    	if (l==x&&r==y) return tree[k];
    	int mid=(x+y)>>1,ll=tree[k].ls,rr=tree[k].rs;
    	if(r<=mid) return ask(ll,l,r);
    	else if (l>mid) return ask(rr,l,r);
    	else
    	{
    		trees t_ans;
    		trees t1=ask(ll,l,mid);
    		trees t2=ask(rr,mid+1,r);
    		t_ans.ans=max(max(t1.ans,t2.ans),t1.rm+t2.lm);
    		t_ans.rm=max(tree[rr].rm,tree[rr].tot+t1.rm);
    		t_ans.lm=max(tree[ll].lm,tree[ll].tot+t2.lm);
    		return t_ans;
    	}
    }
    inline void change(int k,int to,int dat)
    {
    	int x=tree[k].l,y=tree[k].r;
    	if (x==y)
    	{
    		tree[k].tot=tree[k].lm=tree[k].rm=tree[k].ans=dat;
    		return;
    	}
    	int mid=(x+y)>>1;
    	if (to<=mid)change(tree[k].ls,to,dat);
    	if (to>mid)change(tree[k].rs,to,dat);
    	update(k);
    }
    int main()
    {
    	n=read();m=read();
    	for (int i=1;i<=n;i++)
    	a[i]=read();
    	buildtree(1,n);
    	for (int i=1;i<=m;i++)
    	  {
    	  	int x=read(),y=read(),z=read();
    	  	if (x==1)
    	  	{
    	  		if (y>z) swap(y,z);
    	  		printf("%d
    ",ask(1,y,z).ans);
    	  	}else change(1,y,z);
    	  }
    	return 0;
    }


    ——by zhber,转载请注明来源
  • 相关阅读:
    有理有据啊
    男人这辈子挺难的
    最 近 最 NB 的 人
    李安抽了中国电影人一记响亮的耳光
    听LeeHom的几首歌
    【Vegas原创】RMAN06059解决
    【Vegas原创】对应父节点的树状返回查询
    【OU】数据库备份与恢复测试
    【Vegas原创】用x$kvit视图查内部参数设置
    【Vegas原创】DG Build(Linux版)
  • 原文地址:https://www.cnblogs.com/zhber/p/4035964.html
Copyright © 2020-2023  润新知