题目传送:A Simple Problem with Integers
思路:线段树,成段增减,区间求和,注意延迟标记需要累加,还有会爆int
AC代码:
#include <cstdio> #include <cstring> #include <iostream> #include <algorithm> #include <cmath> #include <queue> #include <stack> #include <vector> #include <map> #include <set> #include <deque> #include <cctype> #define LL long long #define INF 0x7fffffff using namespace std; const int maxn = 100005; LL sum[maxn << 2]; LL lazy[maxn << 2]; void pushdown(int rt, int m) { if(lazy[rt] != 0) { lazy[rt << 1] += lazy[rt];//延迟标记需累加,因为可能有别的区间在这里产生延迟标记 lazy[rt << 1 | 1] += lazy[rt]; sum[rt << 1] += (m - (m >> 1)) * lazy[rt];//区间加减更新 sum[rt << 1 | 1] += (m >> 1) * lazy[rt]; lazy[rt] = 0;//用完后记得置为0 } } void build(int l, int r, int rt) {//建树 lazy[rt] = 0;//延迟标记赋初值 if(l == r) { scanf("%I64d", &sum[rt]);//题目中说会爆int,用64位输入输出 return; } int mid = (l + r) >> 1; build(l, mid, rt << 1); build(mid + 1, r, rt << 1 | 1); sum[rt] = sum[rt << 1] + sum[rt << 1 | 1]; } void update(int L, int R, int c, int l, int r, int rt) {//更新 if(L <= l && r <= R) { sum[rt] += (LL)(r - l + 1) * c;//虽然这里不会爆int,但是看到乘法要特别注意会不会爆int lazy[rt] += c;//累加延迟标记 return; } pushdown(rt, r - l + 1); int mid = (l + r) >> 1; if(L <= mid) update(L, R, c, l, mid, rt << 1); if(R >= mid + 1) update(L, R, c, mid + 1, r, rt << 1 | 1); sum[rt] = sum[rt << 1] + sum[rt << 1 | 1]; } LL query(int L, int R, int l, int r, int rt) {//查询 if(L <= l && r <= R) { return sum[rt]; } pushdown(rt, r - l + 1); int mid = (l + r) >> 1; LL ret = 0; if(L <= mid) ret += query(L, R, l, mid, rt << 1); if(R >= mid + 1) ret += query(L, R, mid + 1, r, rt << 1 | 1); return ret; } int main() { int n, q; while(scanf("%d %d", &n, &q) != EOF) { build(1, n, 1); char op[10]; int a, b, c; for(int i = 0; i < q; i ++) { scanf("%s", op); if(op[0] == 'Q') { scanf("%d %d", &a, &b); printf("%I64d\n", query(a, b, 1, n, 1)); } else { scanf("%d %d %d", &a, &b, &c); update(a, b, c, 1, n, 1); } } } return 0; }