Processing math: 100%

CF739C Alyona and towers

题意:维护区间最大的先上升后下降的子段长度,支持区间加

这个题似乎很熟悉,想必你肯定做过它的简化版——最大上升子序列

那么遇到这样的题我们应该怎么做呢,别着急,我们一步一步来

  • 我们肯定是要用线段树维护答案,那么左右儿子怎么合并答案呢,有这么几种情况:

  • 前两种情况就是继承左右儿子的ans
  • 第三种是左儿子中以右端点结尾的ans+右儿子中以左端点开始的最长下降序列长度(左儿子的右端点>右儿子的左端点)
  • 第四种是右儿子中以左端点开始的ans+左儿子中以右端点结束的最长上升序列长度(左儿子的左端点<右儿子的左端点)
  • 维护以左右端点开始或结尾的zans,yans也是类似的,以zans来说

  • 第一种情况就是左儿子的zans
  • 第二种情况是左儿子的zans+右儿子中以左端点开始的最长下降序列长度(左儿子的右端点>右儿子的左端点)
  • 第三种情况是左儿子的区间长度+右儿子的zans(左儿子中以右端点结尾的最长上升序列长度=左儿子的区间长度并且左儿子的右端点<右儿子的左端点)
  • 然后是维护左右端点开始或结束的最长下降或上升的序列长度zlen,ylen,以zlen来说

  • 第一种情况是左儿子的zlen
  • 第二种情况是左儿子的zlen+右儿子的zlen(左儿子的zlen=左儿子的区间长度并且左儿子的右端点>右儿子的左端点)

然后这道题就做完啦

我们整理一下刚才要维护的东西

  • 答案ans

  • 左端点z

  • 右端点y

  • 区间长度len

  • 左端点开始的答案zans

  • 左端点开始的最长下降序列长度zlen

  • 右端点结束的答案yans

  • 右端点结束的最长上升序列长度ylen

至于区间加的操作,对于一个子树而言只影响左右端点,所以正常的打标记下放就可以了

Code

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#define N 300000
#define zrt k << 1
#define yrt k << 1 | 1
using namespace std;
int n,m,a[N + 5];
struct node
{
    int ans,za,ya,zl,yl,len;
    long long z,y,tag;
};
struct Seg
{
    node s[N * 4 + 5];
    node upd(node x,node y)
    {
        node k;
        k.len = x.len + y.len;
        k.z = x.z;
        k.y = y.y;
        k.zl = x.zl;
        if (x.zl == x.len && x.y > y.z)
            k.zl += y.zl;
        k.yl = y.yl;
        if (y.yl == y.len && x.y < y.z)
            k.yl += x.yl;
        k.za = x.za;
        if (k.za == x.len && x.y > y.z)
            k.za += y.zl;
        if (x.yl == x.len && x.y < y.z)
            k.za = max(k.za,x.yl + y.za);
        k.ya = y.ya;
        if (k.ya == y.len && x.y < y.z)
            k.ya += x.yl;
        if (y.zl == y.len && x.y > y.z)
            k.ya = max(k.ya,y.zl + x.ya);
        k.ans = max(x.ans,y.ans);
        if (x.y > y.z)
            k.ans = max(k.ans,x.ya + y.zl);
        if (x.y < y.z)
            k.ans = max(k.ans,y.za + x.yl);
        return k;
    }
    void build(int k,int l,int r)
    {
        if (l == r)
        {
            s[k].ans = 1;
            s[k].ya = 1;
            s[k].za = 1;
            s[k].zl = 1;
            s[k].yl = 1;
            s[k].z = (long long)a[l];
            s[k].y = (long long)a[l];
            s[k].len = 1;
            return;
        }
        int mid = l + r >> 1;
        build(zrt,l,mid);
        build(yrt,mid + 1,r);
        s[k] = upd(s[zrt],s[yrt]);
    }
    void jia(int k,int l,int r,long long z)
    {
        s[k].z += z;
        s[k].y += z;
        s[k].tag += z;
    }
    void pushdown(int k,int l,int r,int mid)
    {
        if (!s[k].tag)
            return;
        jia(zrt,l,mid,s[k].tag);
        jia(yrt,mid + 1,r,s[k].tag);
        s[k].tag = 0;
    }
    void add(int k,int l,int r,int x,int y,long long z)
    {
        if (l >= x && r <= y)
        {
            jia(k,l,r,z);
            return;
        }
        int mid = l + r >> 1;
        pushdown(k,l,r,mid);
        if (x > mid)
            add(yrt,mid + 1,r,x,y,z);
        else
            if (y <= mid)
                add(zrt,l,mid,x,y,z);
            else
                add(zrt,l,mid,x,y,z),add(yrt,mid + 1,r,x,y,z);
        s[k] = upd(s[zrt],s[yrt]);
    }
}tree;
int main()
{
    scanf("%d",&n);
    for (int i = 1;i <= n;i++)
        scanf("%d",&a[i]);
    tree.build(1,1,n);
    scanf("%d",&m);
    int l,r;
    long long z;
    for (int i = 1;i <= m;i++)
    {
        scanf("%d%d%lld",&l,&r,&z);
        tree.add(1,1,n,l,r,z);
        printf("%d\n",tree.s[1].ans);
    }
    return 0;
}
posted @   eee_hoho  阅读(78)  评论(0编辑  收藏  举报
编辑推荐:
· .NET 原生驾驭 AI 新基建实战系列:向量数据库的应用与畅想
· 从问题排查到源码分析:ActiveMQ消费端频繁日志刷屏的秘密
· 一次Java后端服务间歇性响应慢的问题排查记录
· dotnet 源代码生成器分析器入门
· ASP.NET Core 模型验证消息的本地化新姿势
阅读排行:
· 从零开始开发一个 MCP Server!
· ThreeJs-16智慧城市项目(重磅以及未来发展ai)
· .NET 原生驾驭 AI 新基建实战系列(一):向量数据库的应用与畅想
· Ai满嘴顺口溜,想考研?浪费我几个小时
· Browser-use 详细介绍&使用文档
点击右上角即可分享
微信分享提示