BZOJ1756 小白逛公园

BZOJ1756 小白逛公园

题目描述

在小新家附近有一条“公园路”,路的一边从南到北依次排着 n个公园,小白早就看花了眼,自己也不清楚该去哪些公园玩了。

一开始,小白就根据公园的风景给每个公园打了分-.-。小新为了省事,每次遛狗的时候都会事先规定一个范围,

小白只可以选择第 a 个和第 b 个公园之间(包括 a 、 b 两个公园)选择连续的一些公园玩。小白当然希望选出的公园的分数总和尽量高咯。

同时,由于一些公园的景观会有所改变,所以,小白的打分也可能会有一些变化。

那么,就请你来帮小白选择公园吧。

输入格式

第一行,两个整数 N 和 M ,分别表示表示公园的数量和操作(遛狗或者改变打分)总数。

接下来 N 行,每行一个整数,依次给出小白 开始时对公园的打分。
接下来 M行,每行三个整数。第一个整数 K ,1 或 2 。

  • K=1 表示,小新要带小白出去玩,接下来的两个整数 a 和 b 给出了选择公园的范围( 1≤a,b≤N);
  • K=2 表示,小白改变了对某个公园的打分,接下来的两个整数 ps ,表示小白对第 p 个公园的打分变成了 s ( 1≤p≤N )。
    其中, 1≤N≤500 000 , 1≤M≤100 000 ,所有打分都是绝对值不超过 1000 的整数。

 

输出格式

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

Solution

显然的线段树。

每个结点需要维护最大子段和,包含从左端点的最大子段和,包含右端点的最大子段和,然后讨论吧

主要就是pushdown比较麻烦。

#include<bits/stdc++.h>

using namespace std;

const int MAXN = 500000 + 10;
typedef long long ll;

inline ll read()
{
    ll f=1,x=0;
    char ch;
    do
    {
        ch=getchar();
        if(ch=='-') f=-1;
    }while(ch<'0'||ch>'9');
    do
    {
        x=(x<<3)+(x<<1)+ch-'0';
        ch=getchar();
    }while(ch>='0'&&ch<='9');
    return f*x;
}

int n,m;
int a[MAXN];

struct node
{
    int l,r;
    int lmax,rmax,sum,ans;
    inline int mid()
    {
        return (l+r)>>1;
    }
};node tree[MAXN*4];

#define lc o<<1
#define rc o<<1|1

inline void pushup(int o)
{
    tree[o].sum=tree[lc].sum+tree[rc].sum;
    tree[o].lmax=max(tree[lc].lmax,tree[lc].sum+tree[rc].lmax);
    tree[o].rmax=max(tree[rc].rmax,tree[rc].sum+tree[lc].rmax);
    tree[o].ans=max(max(tree[lc].ans,tree[rc].ans),tree[lc].rmax+tree[rc].lmax);
    return;
}

inline void build(int o,int l,int r)
{
    tree[o].l=l;tree[o].r=r;
    if(l==r)
    {
        tree[o].sum=a[l];
        tree[o].lmax=tree[o].rmax=tree[o].ans=a[l];
        return;
    }
    int mid=tree[o].mid();
    build(lc,l,mid);
    build(rc,mid+1,r);
    pushup(o);
}

inline void update(int o,int x,int y)
{
    int l = tree[o].l,r=tree[o].r;
    if(l==r)
    {
        tree[o].sum=y;
        tree[o].lmax=tree[o].rmax=tree[o].ans=y;
        //cout<<l<<" "<<tree[o].sum<<endl;
        return;
    }
    int mid=tree[o].mid();
    if(x<=mid)
    update(lc,x,y);
    else
    update(rc,x,y);
    pushup(o);
}

inline node query(int o,int x,int y)
{
    int l =tree[o].l,r=tree[o].r;
    if(l>=x&&r<=y) return tree[o];
    else
    {
        int mid = tree[o].mid();
        if(y<=mid) return query(lc,x,y);
        else if(x>mid) return query(rc,x,y);
        else
        {
            node t = query(lc,x,y);
            node t1 = query(rc,x,y);
            node now;
            now.lmax=max(t.lmax,t.sum+t1.lmax);
            now.rmax=max(t1.rmax,t1.sum+t.rmax);
            now.ans=max(max(t.ans,t1.ans),t.rmax+t1.lmax);
            return now;
        }
    }
}

int main()
{
    n = read();m = read();
    for(int i=1;i<=n;i++)
        a[i]=read();
    build(1,1,n);
    for(int i=1;i<=m;i++)
    {
        int k=read(),x=read(),y=read();
        if(k==1)
        {
            if(x>y) swap(x,y);
            cout<<query(1,x,y).ans<<endl;
        }
        if(k==2)
        {
            update(1,x,y);
        }
    }
 } 

然后update里脑抽写错一行,调了好久。。。

inline void update(int o,int x,int y)
{
    int l = tree[o].l,r=tree[o].r;
    if(l==r)
    {
        tree[o].sum=y;
        tree[o].lmax=tree[o].rmax=tree[o].ans=y;
        //cout<<l<<" "<<tree[o].sum<<endl;
        return;
    }
    int mid=tree[o].mid();
    if(x<=mid)
    build(lc,x,y);//??!
    else
    build(rc,x,y);//??!
    pushup(o);
}

我也不知道上面的代码我是怎么打出来的

posted @ 2018-06-14 19:42  wlzs1432  阅读(231)  评论(0编辑  收藏