• 【vijos】P1083 小白逛公园


    【算法】线段树

    【题解】

    学自:https://vijos.org/p/1083/solution(wang_yanheng的回答)

    回溯时维护一段区间的以下域:

    • sumL:从左端点起连续区间的最大和
    • sumR:从右端点起连续区间的最大和
    • sum:整段区间的和
    • subSum:最大子区间和

    以上域在叶子节点中的值,都等于节点代表公园的评分
    设当前节点为 x,左孩子为 l,右孩子为 r。则:

    x.sumL = MAX(l.sumL, l.sum + r.sumL);
    x.sumR = MAX(r.sumR, r.sum + l.sumR);
    x.sum = l.sum + r.sum;
    x.subSum = MAX(l.subSum, r.subSum, l.sumR + r.sumL);
    以上计算过程可以写成函数,参数结构体,返回结构体。
    查询时要返回结构体。
    #include<cstdio>
    #include<algorithm>
    using namespace std;
    const int inf=0x3f3f3f3f,maxn=500010;
    struct cyc{int lsum,rsum,sum,subsum;}t[maxn*3];
    int a[maxn],L[maxn*3],R[maxn*3],n,m;
    cyc calc(cyc a,cyc b)
    {
        cyc c;
        c.lsum=max(a.lsum,a.sum+b.lsum);
        c.rsum=max(b.rsum,b.sum+a.rsum);
        c.sum=a.sum+b.sum;
        c.subsum=max(a.subsum,max(b.subsum,a.rsum+b.lsum));
        return c;
    }
    void build(int k,int l,int r)
    {
        L[k]=l;R[k]=r;
        if(l==r)t[k]={a[l],a[l],a[l],a[l]};
         else
          {
             int mid=(l+r)>>1;
             build(k<<1,l,mid);
             build(k<<1|1,mid+1,r);
             t[k]=calc(t[k<<1],t[k<<1|1]);
          } 
    }
    void update(int k,int x,int num)
    {
        int left=L[k],right=R[k];
        if(left==right)t[k]={num,num,num,num};
         else
          {
             int mid=(left+right)>>1;
             if(x<=mid)update(k<<1,x,num);
              else update(k<<1|1,x,num);
             t[k]=calc(t[k<<1],t[k<<1|1]);
          }
    }
    cyc ask(int k,int l,int r)
    {
        int left=L[k],right=R[k];
        if(l<=left&&right<=r)return t[k];
         else
          {
              int mid=(left+right)>>1;
              if(l>mid)return ask(k<<1|1,l,r);
              if(r<=mid)return ask(k<<1,l,r);
              return calc(ask(k<<1,l,r),ask(k<<1|1,l,r));
          }
    }
    int main()
    {
        scanf("%d%d",&n,&m);
        for(int i=1;i<=n;i++)scanf("%d",&a[i]);
        build(1,1,n);
        for(int i=1;i<=m;i++)
         {
             int k,b,c;
             scanf("%d%d%d",&k,&b,&c);
             if(k==1)
              {
                  if(b>c)swap(b,c);
                printf("%d
    ",ask(1,b,c).subsum);
             }
            else update(1,b,c);
         }
    }
    View Code
     
  • 相关阅读:
    dpkg安装deb缺少依赖包的解决方法
    一个linux命令之grep---1
    win10快捷键
    Windows Server 2008 R2遗忘管理员密码后的解决方案
    手工释放linux内存
    oracle数据库用户加锁和解锁
    完全卸载Oracle数据库软件
    Linux上VNC 启动和关闭常见问题
    Linux 开启VNCSERVER
    RedHat 简易配置 VNC Server 与VNC View详细说明
  • 原文地址:https://www.cnblogs.com/onioncyc/p/5795052.html
Copyright © 2020-2023  润新知