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;
}
【推荐】还在用 ECharts 开发大屏?试试这款永久免费的开源 BI 工具!
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· .NET 原生驾驭 AI 新基建实战系列:向量数据库的应用与畅想
· 从问题排查到源码分析:ActiveMQ消费端频繁日志刷屏的秘密
· 一次Java后端服务间歇性响应慢的问题排查记录
· dotnet 源代码生成器分析器入门
· ASP.NET Core 模型验证消息的本地化新姿势
· 从零开始开发一个 MCP Server!
· ThreeJs-16智慧城市项目(重磅以及未来发展ai)
· .NET 原生驾驭 AI 新基建实战系列(一):向量数据库的应用与畅想
· Ai满嘴顺口溜,想考研?浪费我几个小时
· Browser-use 详细介绍&使用文档