Spoj 1716 Can you answer these queries III 线段树 单点修改 区间求最大子段和

题目链接:点击打开链接

== 原来写1的时候已经把更新函数写好了。。

#include <cstdio>
#include <iostream>
#include <algorithm>
#include <string.h>
#include <math.h>
#include <vector>
#include <map>
using namespace std;
#define N 50050
#define Lson(x) tree[x].l
#define Rson(x) tree[x].r
#define L(x) (x<<1)
#define R(x) (x<<1|1)
#define Sum(x) tree[x].sum
#define Max(x) tree[x].max
#define Lmax(x) tree[x].lmax
#define Rmax(x) tree[x].rmax
struct node{
    int l, r;
    int mid(){return (l+r)>>1;}
    int lmax, rmax, max, sum;
}tree[N<<2];
int n, a[N], Q;
void push_down(int id){}
void push_up(int id){
    Lmax(id) = max(Lmax(L(id)), Sum(L(id)) + Lmax(R(id)));
    Rmax(id) = max(Rmax(R(id)), Sum(R(id)) + Rmax(L(id)));
    Sum(id) = Sum(L(id)) + Sum(R(id));
    Max(id) = max(max(Max(L(id)), Max(R(id))), Rmax(L(id)) + Lmax(R(id)));
}
void updata_point(int val, int id){Lmax(id) = Rmax(id) = Max(id) = Sum(id) = val;}
void build(int l, int r, int id){
    Lson(id) = l; Rson(id) = r;
    if(l == r)
    {
        updata_point(a[l], id);
        return;
    }
    int mid = tree[id].mid();
    build(l, mid, L(id));
    build(mid+1, r, R(id));
    push_up(id);
}
void updata(int pos, int val, int id){
    push_down(id);
    if(Lson(id) == Rson(id))
    {
        updata_point(val, id);
        return ;
    }
    int mid = tree[id].mid();
    if(mid < pos)
        updata(pos, val, R(id));
    else
        updata(pos, val, L(id));
    push_up(id);
}
int query_l(int l, int r, int id){
    push_down(id);
    if(l == Lson(id) && Rson(id) == r) return Lmax(id);
    int mid = tree[id].mid();
    if(mid < l)
        return query_l(l, r, R(id));
    else if(r <= mid)
        return query_l(l, r, L(id));
    int lans = query_l(l, mid, L(id)), rans = query_l(mid+1, r, R(id));
    return max(lans, Sum(L(id)) + rans);
}
int query_r(int l, int r, int id){
    push_down(id);
    if(l == Lson(id) && Rson(id) == r) return Rmax(id);
    int mid = tree[id].mid();
    if(mid < l)
        return query_r(l, r, R(id));
    else if(r <= mid)
        return query_r(l, r, L(id));
    int lans = query_r(l, mid, L(id)), rans = query_r(mid+1, r, R(id));
    return max(rans, Sum(R(id)) + lans);
}
int query(int l, int r, int id){
    push_down(id);
    if(l == Lson(id) && Rson(id) == r)return Max(id);
    int mid = tree[id].mid();
    if(mid < l)
        return query(l, r, R(id));
    else if(r<=mid)
        return query(l, r, L(id));
    int lans = query(l, mid, L(id)), rans = query(mid+1, r, R(id));
    int ans = max(lans, rans);
    return max(ans, query_r(l, mid, L(id)) + query_l(mid+1, r, R(id)));
}
int main(){
    while(~scanf("%d",&n)){
        for(int i = 1; i <= n; i++)scanf("%d",&a[i]);
        build(1, n, 1);
        scanf("%d",&Q);
        while(Q--){
            int l, r, op;
            scanf("%d %d %d", &op, &l, &r);
            if(op == 1)
                printf("%d\n", query(l, r, 1));
            else
                updata(l, r, 1);
        }
    }
    return 0;
}
/*
3
-1 2 3
1
1 2

*/
时间: 2024-12-25 00:27:36

Spoj 1716 Can you answer these queries III 线段树 单点修改 区间求最大子段和的相关文章

SPOJ GSS3 Can you answer these queries III (线段树)

题目大意: 求区间最大子区间的和. 思路分析: 记录左最大,右最大,区间最大. 注意Q_L  和 Q_R  就好. #include <cstdio> #include <iostream> #include <algorithm> #include <cstring> #define lson num<<1,s,mid #define rson num<<1|1,mid+1,e #define maxn 55555 using na

SPOJ GSS3 Can you answer these queries III ——线段树

[题目分析] GSS1的基础上增加修改操作. 同理线段树即可,多写一个函数就好了. [代码] #include <cstdio> #include <cstring> #include <cmath> #include <cstdlib> #include <map> #include <set> #include <queue> #include <string> #include <iostream&

SPOJ GSS4 Can you answer these queries IV (线段树)

题目大意: 给出N个数 0     操作   把 l -----  r之间的数全部开平方 1     操作  输出 l -----r  之间的和 思路分析: 判断区间里的数字是否全相同.如果相同, 将cov 置为该数 查询的时候和更新的时候,如果碰到cov != -1 的  就直接返回就可以了 #include <cstdio> #include <iostream> #include <algorithm> #include <cstring> #incl

SP1716 GSS3 - Can you answer these queries III 线段树

题目传送门:SP1043 GSS1 - Can you answer these queries I 更好的阅读体验 动态维护子段和最大值 前置知识 静态维护子段和最大值:SP1043 GSS1 - Can you answer these queries I 题解传送 题解: 提供结构体指针线段树写法: 设\(l\)为区间左端点, \(r\)为区间右端点: \(ls\)为以\(l\)为左端点的最大子段和, \(rs\)为以\(r\)为右端点的最大子段和; \(sum\)为区间和, \(val\

bzoj 2482: [Spoj GSS2] Can you answer these queries II 线段树

2482: [Spoj1557] Can you answer these queries II Time Limit: 20 Sec  Memory Limit: 128 MBSubmit: 145  Solved: 76[Submit][Status][Discuss] Description 给定n个元素的序列. 给出m个询问:求l[i]~r[i]的最大子段和(可选空子段). 这个最大子段和有点特殊:一个数字在一段中出现了两次只算一次. 比如:1,2,3,2,2,2出现了3次,但只算一次,

SPOJ 1557. Can you answer these queries II 线段树

Can you answer these queries II Time Limit: 20 Sec Memory Limit: 256 MB 题目连接 https://www.spoj.com/problems/GSS2/ Description Being a completist and a simplist, kid Yang Zhe cannot solve but get Wrong Answer from most of the OI problems. And he refuse

spoj 1716 Can you answer these queries III(线段树)

和I相比有了单点更新,所以不能只记录一个前缀和,而是要在线段树上多维护一个sum,表示这个结点的区间和,然后其他的就和I一样了. #include <iostream>#include <cstring>#include <cstdio>using namespace std; const int N = 50001;int a[N]; struct Node { int l, r, sum; int maxl, maxr, maxn;} node[N <<

SPOJ GSS5 Can you answer these queries V ——线段树

[题目分析] GSS1上增加区间左右端点的限制. 直接分类讨论就好了. [代码] #include <cstdio> #include <cstring> #include <cmath> #include <cstdlib> #include <map> #include <set> #include <queue> #include <string> #include <iostream> #i

Spoj 2916 Can you answer these queries V 线段树 求任意重叠区间的最大子段和

题目链接:点击打开链接 题意: T个测试数据 n个数字 q个询问 每个询问 : [x1, y1] [x2, y2] 问: int ans = -inf; for(int i = x1; i <= y1; i++) for(int j = max(x2, i); j <= y2; j++) ans = max(ans, query(i, j)); 思路: query_L(int l, int r) 求的是在区间[l,r]内 ,左端点为l的最大子段和. 其他和GSS3差不多. 分类讨论一下给定的区