AcWing
  • 首页
  • 课程
  • 题库
  • 更多
    • 竞赛
    • 题解
    • 分享
    • 问答
    • 应用
    • 校园
  • 关闭
    历史记录
    清除记录
    猜你想搜
    AcWing热点
  • App
  • 登录/注册

AcWing 245. $\Large\color{blue}{【算法提高课】你能回答这些问题吗(线段树)}$    原题链接    简单

作者: 作者的头像   incra ,  2022-11-06 08:26:43 ,  所有人可见 ,  阅读 1277


22


<—点个赞吧QwQ

宣传一下算法提高课整理{:target=”_blank”}

给定长度为 $N$ 的数列 $A$,以及 $M$ 条指令,每条指令可能是以下两种之一:

  1. 1 x y,查询区间 $\[x,y\]$ 中的最大连续子段和,即 $\\max\\limits_{x \\le l \\le r \\le y}${$\\sum\\limits^r_{i=l} A\[i\]$}。
  2. 2 x y,把 $A\[x\]$ 改成 $y$。

对于每个查询指令,输出一个整数表示答案。

输入格式

第一行两个整数 $N,M$。

第二行 $N$ 个整数 $A\[i\]$。

接下来 $M$ 行每行 $3$ 个整数 $k,x,y$,$k=1$ 表示查询(此时如果 $x>y$,请交换 $x,y$),$k=2$ 表示修改。

输出格式

对于每个查询指令输出一个整数表示答案。

每个答案占一行。

数据范围

$N \\le 500000, M \\le 100000$,
$\-1000 \\le A\[i\] \\le 1000$

输入样例:

5 3
1 2 -3 4 5
1 2 3
2 2 -1
1 3 2

输出样例:

2
-1

思路

线段树经典题。

考虑由左右两个区间子区间$tl,tr$得到当前区间的最大子段和$ans$,则有
$ans=\max\lbrace$$tl$的最大子段和,$tr$的最大子段和,跨越区间中点的最大子段和$\rbrace$
$tl$的最大子段和$\&tr$的最大子段和递归求即可。
跨越中点的的最大子段和$=$tl右端点起的向左的最大子段和$+$tr左端点起的向右的最大子段和

所以线段树上每个节点维护四个信息:

  1. $maxl$:左端点起的向右的最大子段和
  2. $maxr$:右端点起的向左的最大子段和
  3. $maxt$整个区间的最大子段和
  4. $sum$:区间和

然后$pushup$时这四个信息都更新一下即可。

代码

#include <iostream>
using namespace std;
const int N = 500010;
int n,m;
int a[N];
struct Node {
    int l,r;
    int tmax,lmax,rmax,sum;
}tr[4 * N];
void pushup (Node &u,Node &l,Node &r) {
    u.sum = l.sum + r.sum;
    u.lmax = max (l.lmax,l.sum + r.lmax);
    u.rmax = max (r.rmax,r.sum + l.rmax);
    u.tmax = max (max (l.tmax,r.tmax),l.rmax + r.lmax);
}
void pushup (int u) {
    pushup (tr[u],tr[u * 2],tr[u * 2 + 1]);
}
void build (int u,int l,int r) {
    if (l == r) tr[u] = {l,r,a[l],a[l],a[l],a[l]};
    else {
        tr[u].l = l,tr[u].r = r;
        int mid = l + r >> 1;
        build (u * 2,l,mid),build (u * 2 + 1,mid + 1,r);
        pushup (u);
    }
}
int modify (int u,int x,int v) {
    if (tr[u].l == x && tr[u].r == x) tr[u] = {x,x,v,v,v,v};
    else {
        int mid = tr[u].l + tr[u].r >> 1;
        if (x <= mid) modify (u * 2,x,v);
        else modify (u * 2 + 1,x,v);
        pushup (u);
    }
}
Node query (int u,int l,int r) {
    if (tr[u].l >= l && tr[u].r <= r) return tr[u];
    else {
        int mid = tr[u].l + tr[u].r >> 1;
        if (r <= mid) return query (u * 2,l,r);
        if (l > mid) return query (u * 2 + 1,l,r);
        Node left = query (u * 2,l,r);
        Node right = query (u * 2 + 1,l,r);
        Node ans;
        pushup (ans,left,right);
        return ans;
    }
}
int main () {
    cin >> n >> m;
    for (int i = 1;i <= n;i++) cin >> a[i];
    build (1,1,n);
    while (m--) {
        int x,l,r;
        cin >> x >> l >> r;
        if (x == 1) {
            if (l > r) swap (l,r);
            cout << query (1,l,r).tmax << endl;
        }
        else modify (1,l,r);
    }
    return 0;
}

3 评论


用户头像
谢锋   2023-03-25 18:01      1    踩      回复

build函数的else块中,不加上tr[u].l = l, tr[u].r = r为啥会segementation fault?

用户头像
incra   2023-03-25 18:29      1    踩      回复

不加的话相当于没表示这个区间表示的范围。


用户头像
ququ   2023-01-09 09:08         踩      回复

Good!


App 内打开
你确定删除吗?
1024
x

© 2018-2025 AcWing 版权所有  |  京ICP备2021015969号-2
用户协议  |  隐私政策  |  常见问题  |  联系我们
AcWing
请输入登录信息
更多登录方式: 微信图标 qq图标 qq图标
请输入绑定的邮箱地址
请输入注册信息