题目描述
在人气动漫 Black Rock shooter 中,当加贺里对麻陶 说出了“滚回去“以后,与此同时,在另一个心灵世界里, BRS 也遭到了敌人的攻击。此时,一共有 n 个攻击排成一行 朝着她飞了过来,每个攻击有一个伤害值。并且每个攻击伤 害可能随时变化。BRS 的攻击可以打掉一段连续的攻击。现 在,给出 m 段攻击,求出 BRS 最多可以打掉此段里多少的 伤害(就是说从给定一段里选择连续一段打掉)。伤害从 1 到 n 编号。
输入输出格式
输入格式:
第一行 2 个整数:n , m
第二行 n 个数:第 i 个数代表第 i 个攻击
第 3 到 2+m 行:每行三个数 k,x,y。若 k=1,x,y 代表查询的区间。若 k=2,代表第 x 个攻击伤害改为了 y 所有的伤害值绝对值<=1000
输出格式:
对于每次 k=1,输出一个整数代表最大值
题解
有题目可知这道题要求最大区间子段和,考虑用线段树维护。
对于线段树的每个节点,我们要储存四个信息:
typedef struct Node { int l, r; long long lsum, rsum, msum, sum; //lsum:从左边开始的最长子段和 //rsum:从右边开始的最长子段和 //msum:整个区间中的最长子段和 //sum:整个区间的子段和 Node *lson, *rson; Node(): l(0), r(0), lsum(0), rsum(0), msum(0), lson(NULL), rson(NULL), sum(0) {} int len() {return r - l;} int mid() {return (l + r) >> 1;} }node, *pointer;
对于每个变量,我们要在PushUp操作中进行维护:
void PsuhUp(pointer rt) { rt->sum = rt->lson->sum + rt->rson->sum; //和的维护是直接维护 rt->lsum = std::max(rt->lson->lsum, rt->lson->sum + rt->rson->lsum); //从左边开始的最长子段和有可能就是左边的最长子段和也有可能是整个左子树加上右子树的左边最长子段和 rt->rsum = std::max(rt->rson->rsum, rt->rson->sum + rt->lson->rsum); //右边同理 rt->msum = std::max(rt->lson->rsum + rt->rson->lsum, std::max(rt->lson->msum, rt->rson->msum)); //中间的最长子段和除了要比较左右子树的两个之外,还要考虑将两个子树区间合并后新产生的的一个子段 }
最麻烦的是查询操作,同样也分为两种情况:
一种是在一个区间的中间的最长子段和,一种是有两个子树的左右最长子段和拼起来的。
//前面两个query操作是为了考虑第二种情况
LL QueryR(pointer rt, LL x, LL y) { if(rt->l >= x && y >= rt->r) return rt->rsum; LL ans = QueryR(rt->rson, x, y); if(x < rt->mid()) ans = std::max(ans, QueryR(rt->lson, x, y) + rt->rson->sum); return ans; } LL QueryL(pointer rt, LL x, LL y) { if(rt->l >= x && y >= rt->r) return rt->lsum; LL ans = QueryL(rt->lson, x, y); if(y > rt->mid()) ans = std::max(ans, QueryL(rt->rson, x, y) + rt->lson->sum); return ans; } LL Query(pointer rt, LL x, LL y) { if(x <= rt->l && rt->r <= y) return rt->msum; LL ans = -0x7fffffff; if(y <= rt->mid()) ans = Query(rt ->lson, x, y); //整个区间都在左子树上 else if(x >= rt->mid()) ans = Query(rt->rson, x, y); //整个区间都在右子树上 else ans = std::max(QueryR(rt->lson, x, y) + QueryL(rt->rson, x, y), std::max(Query(rt->lson, x, y), Query(rt->rson, x, y)));
//区间分布在左右子树上 return ans; }
代码
#include <bits/stdc++.h> using namespace std; #define LL long long const int MAX = 500005; typedef struct Node { int l, r; long long lsum, rsum, msum, sum; Node *lson, *rson; Node(): l(0), r(0), lsum(0), rsum(0), msum(0), lson(NULL), rson(NULL), sum(NULL) {} int len() {return r - l;} int mid() {return (l + r) >> 1;} }node, *pointer; class Segement_Tree { private: void PsuhUp(pointer rt) { rt->sum = rt->lson->sum + rt->rson->sum; rt->lsum = max(rt->lson->lsum, rt->lson->sum + rt->rson->lsum); rt->rsum = max(rt->rson->rsum, rt->rson->sum + rt->lson->rsum); rt->msum = max(rt->lson->rsum + rt->rson->lsum, max(rt->lson->msum, rt->rson->msum)); } LL QueryR(pointer rt, LL x, LL y) { if(rt->l >= x && y >= rt->r) return rt->rsum; LL ans = QueryR(rt->rson, x, y); if(x < rt->mid()) ans = max(ans, QueryR(rt->lson, x, y) + rt->rson->sum); return ans; } LL QueryL(pointer rt, LL x, LL y) { if(rt->l >= x && y >= rt->r) return rt->lsum; LL ans = QueryL(rt->lson, x, y); if(y > rt->mid()) ans = max(ans, QueryL(rt->rson, x, y) + rt->lson->sum); return ans; } public: pointer root = new Node(); LL a[MAX]; void Build(pointer rt, int l, int r) { rt->r = r, rt->l = l; if(r - l == 1) { rt->lsum = a[l], rt->rsum = a[l], rt->msum = a[l], rt->sum = a[l]; return ; } rt->lson = new Node(), rt->rson = new Node(); Build(rt->lson, l, rt->mid()), Build(rt->rson, rt->mid(), r); PsuhUp(rt); return ; } void Updata(pointer rt, LL x, LL y) { if(rt->r - rt->l == 1 && rt->l == x) { rt->lsum = y, rt->rsum = y, rt->msum = y, rt->sum = y; return ; } if(x < rt->mid()) Updata(rt->lson, x, y); else Updata(rt->rson, x, y); PsuhUp(rt); } LL Query(pointer rt, LL x, LL y) { if(x <= rt->l && rt->r <= y) return rt->msum; LL ans = -0x7fffffff; if(y <= rt->mid()) ans = Query(rt ->lson, x, y); else if(x >= rt->mid()) ans = Query(rt->rson, x, y); else ans = max(QueryR(rt->lson, x, y) + QueryL(rt->rson, x, y), max(Query(rt->lson, x, y), Query(rt->rson, x, y))); return ans; } }; Segement_Tree tree; inline long long Qread() { long long x = 0; int w = 0; char ch = getchar(); for(;!isdigit(ch); w |= (ch == '-'), ch= getchar()); for(;isdigit(ch);x = (x << 3) + (x << 1) + (ch ^ 48), ch = getchar()); return w ? -x : x; } inline int qread() { int x = 0; int w = 0; char ch = getchar(); for(;!isdigit(ch); w |= (ch == '-'), ch= getchar()); for(;isdigit(ch);x = (x << 3) + (x << 1) + (ch ^ 48), ch = getchar()); return w ? -x : x; } int main() { // freopen("BRS.in", "r", stdin); // freopen("BRS.out", "w", stdout); int n, m; LL opt, x, y; memset(tree.a, 0, sizeof(tree.a)); scanf("%d%d", &n, &m); for(int i = 1; i <= n; ++ i) tree.a[i] = Qread(); tree.Build(tree.root, 1, n + 1); for(int i = 1; i <= m; ++ i) { opt = Qread(), x = Qread(), y = Qread(); if(opt == 1) printf("%lld ", tree.Query(tree.root, x, y + 1)); if(opt == 2) tree.Updata(tree.root, x, y); } }