问题描述
有n个格子,从左到右放成一排,编号为1-n。
共有m次操作,有3种操作类型:
1.修改一个格子的权值,
2.求连续一段格子权值和,
3.求连续一段格子的最大值。
对于每个2、3操作输出你所求出的结果。
输入格式
第一行2个整数n,m。
接下来一行n个整数表示n个格子的初始权值。
接下来m行,每行3个整数p,x,y,p表示操作类型,p=1时表示修改格子x的权值为y,p=2时表示求区间[x,y]内格子权值和,p=3时表示求区间[x,y]内格子最大的权值。
输出格式
有若干行,行数等于p=2或3的操作总数。
每行1个整数,对应了每个p=2或3操作的结果。
样例输入
4 3
1 2 3 4
2 1 3
1 4 3
3 1 4
1 2 3 4
2 1 3
1 4 3
3 1 4
样例输出
6
3
3
数据规模与约定
对于20%的数据n <= 100,m <= 200。
对于50%的数据n <= 5000,m <= 5000。
对于100%的数据1 <= n <= 100000,m <= 100000,0 <= 格子权值 <= 10000。
练习了一下线段树,习惯了敲模板,蓝桥杯却不能看模板,赶脚好痛苦。。。
#include <cstdio> #include <algorithm> #define N 1000005 #define ll long long using namespace std; ll sum[N] = {0}; ll Max[N] = {0}; void PushUp(int rt) { Max[rt] = max(Max[rt << 1], Max[rt << 1 | 1]); sum[rt] = sum[rt << 1] + sum[rt << 1 | 1]; } void Build(int rt, int l, int r) { if(l == r) { scanf("%I64d", &sum[rt]); Max[rt] = sum[rt]; } else { int m = (l + r) >> 1; Build(rt << 1, l, m); Build(rt << 1 | 1, m + 1, r); PushUp(rt); } } void UpDate(int p, int val, int l, int r, int rt) { if(l == r) { sum[rt] = val; Max[rt] = val; } else { int m = (l + r) >> 1; if(p <= m) UpDate(p, val, l, m, rt << 1); else UpDate(p, val, m + 1, r, rt << 1 | 1); PushUp(rt); } } ll Query_max(int L, int R, int l, int r, int rt) { if(L <= l && R >= r) return Max[rt]; else { int m = (l + r) >> 1; ll ans = 0; if(L <= m) ans = max(Query_max(L, R, l, m, rt << 1), ans); if(R > m) ans = max(Query_max(L, R, m + 1 , r, rt << 1 | 1), ans); return ans; } } ll Query_sum(int L, int R, int l, int r, int rt) { if(L <= l && R >= r) return sum[rt]; else { int m = (l + r) >> 1; ll ans = 0; if(L <= m) ans += Query_sum(L, R, l, m, rt << 1); if(m < R) ans += Query_sum(L, R, m + 1 , r, rt << 1 | 1); return ans; } } int main() { int n, q; scanf("%d%d", &n, &q); Build(1, 1, n); for(int i = 0; i < q; i++) { int op, a, b; scanf("%d%d%d", &op, &a, &b); if(op == 1) UpDate(a, b, 1, n, 1); else if(op == 2) printf("%I64d ", Query_sum(a, b, 1, n, 1)); else printf("%I64d ", Query_max(a, b, 1, n, 1)); } return 0; }