0x43 Can you answer on these queries III(线段树)

好久之前(好像是去年5月)做过的题,居然没做出来就弃疗了,今天才发现

问题的本质其实是询问区间最大和

用线段树怎么上传?

子树上传到根的最大字段分成两种情况:

  • 不经过终点,是两段的最大值
  • 经过中点

经过中点怎么完成?

定义:

d a t dat dat 表示区间最大字段和
s u m sum sum 表示区间和
l m a x lmax lmax 表示区间左端点的最大子段和
r m a x rmax rmax 表示区间右端点的最大子段和

怎么上传?

s u m sum sum 直接上传,
l m a x [ x ] = m a x ( l m a x [ l ] , s u m [ l ] + l m a x [ r ] ) lmax[x]=max(lmax[l],sum[l]+lmax[r]) lmax[x]=max(lmax[l],sum[l]+lmax[r])
r m a x [ x ] = m a x ( r m a x [ r ] , s u m [ r ] + r m a x [ l ] ) rmax[x]=max(rmax[r],sum[r]+rmax[l]) rmax[x]=max(rmax[r],sum[r]+rmax[l])
d a t [ x ] = m a x ( d a t [ l ] + d a t [ r ] , l m a x [ l ] + l m a x [ r ] ) dat[x]=max(dat[l]+dat[r],lmax[l]+lmax[r]) dat[x]=max(dat[l]+dat[r],lmax[l]+lmax[r])

#include <map>
#include <set>
#include <ctime>
#include <queue>
#include <stack>
#include <cmath>
#include <vector>
#include <bitset>
#include <cstdio>
#include <cctype>
#include <string>
#include <numeric>
#include <cstring>
#include <cassert>
#include <climits>
#include <cstdlib>
#include <iostream>
#include <algorithm>
#include <functional>
using namespace std ;
#define rep(i, a, b) for (int i = (a); i <= (b); i++)
#define per(i, a, b) for (int i = (a); i >= (b); i--)
#define loop(s, v, it) for (s::iterator it = v.begin(); it != v.end(); it++)
#define cont(i, x) for (int i = head[x]; i; i = e[i].nxt)
#define clr(a) memset(a, 0, sizeof(a))
#define ass(a, sum) memset(a, sum, sizeof(a))
#define lowbit(x) (x & -x)
#define all(x) x.begin(), x.end()
#define mp make_pair
#define pb push_back
#define fi first
#define se second
#define iv inline void
#define enter cout << endl
#define siz(x) ((int)x.size())
#define file(s) freopen(s".in", "r", stdin), freopen(s."out", "w", stdout)
typedef long long ll ;
typedef unsigned long long ull ;
typedef pair <int, int> pii ;
typedef vector <int> vi ;
typedef vector <pii> vii ;
typedef queue <int> qi ;
typedef set <int> si ;
typedef map <int, int> mii ;
typedef map <string, int> msi ;
const int N = 50010 ;
const int INF = 0x3f3f3f3f ;
const int iinf = 1 << 30 ;
const ll linf = 2e18 ;
const int MOD = 1000000007 ;
const double eps = 1e-7 ;
void print(int x) { cout << x << endl ; exit(0) ; }
void PRINT(string x) { cout << x << endl ; exit(0) ; }
void douout(double x){ printf("%lf\n", x + 0.0000000001) ; }

int n, m ;
int a[N] ;

struct Tree {
    int lmax, rmax, sum, dat ;
} tr[N << 2] ;

#define ls x << 1
#define rs x << 1 | 1

void pushup(int x) {
    Tree l = tr[ls], r = tr[rs] ;
    tr[x].sum = l.sum + r.sum ;
    tr[x].lmax = max(l.lmax, l.sum + r.lmax) ;
    tr[x].rmax = max(r.rmax, r.sum + l.rmax) ;
    tr[x].dat = max(l.rmax + r.lmax, max(l.dat, r.dat)) ;
}

void build(int x, int l, int r) {
    if (l == r) {
        tr[x].dat = tr[x].lmax = tr[x].rmax = tr[x].sum = a[l] ;
        return ;
    }
    int mid = (l + r) >> 1 ;
    build(ls, l, mid) ;
    build(rs, mid + 1, r) ;
    pushup(x) ;
}

void modify(int x, int l, int r, int pos, int val) {
    if (l == r) {
        tr[x].dat = tr[x].lmax = tr[x].rmax = tr[x].sum = val ;
        return ;
    }
    int mid = (l + r) >> 1 ;
    if (pos <= mid) modify(ls, l, mid, pos, val) ;
    else modify(rs, mid + 1, r, pos, val) ;
    pushup(x) ;
}

Tree query(int x, int l, int r, int X, int Y) {
    if (X <= l && r <= Y) return tr[x] ;
    int mid = (l + r) >> 1 ;
    if (Y <= mid) return query(ls, l, mid, X, Y) ;
    if (X > mid) return query(rs, mid + 1, r, X, Y) ;
    Tree L = query(ls, l, mid, X, mid), R = query(rs, mid + 1, r, mid + 1, Y), res ;
    res.sum = L.sum + R.sum ;
    res.lmax = max(L.lmax, L.sum + R.lmax) ;
    res.rmax = max(R.rmax, R.sum + L.rmax) ;
    res.dat = max(L.rmax + R.lmax, max(L.dat, R.dat)) ;
    return res ;
}

signed main(){
    scanf("%d", &n) ;
    rep(i, 1, n) scanf("%d", &a[i]) ;
    build(1, 1, n) ;
    scanf("%d", &m) ;
    while (m--) {
        int op, x, y ; scanf("%d%d%d", &op, &x, &y) ;
        if (op == 0) modify(1, 1, n, x, y) ;
        else printf("%d\n", query(1, 1, n, x, y).dat) ;
    }
    return 0 ;
}

/*
写代码时请注意:
    1.ll?数组大小,边界?数据范围?
    2.精度?
    3.特判?
    4.至少做一些
思考提醒:
    1.最大值最小->二分?
    2.可以贪心么?不行dp可以么
    3.可以优化么
    4.维护区间用什么数据结构?
    5.统计方案是用dp?模了么?
    6.逆向思维?
*/




  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值