题目链接:http://ccnu.acmclub.com/index.php?app=problem_title&id=613&problem_id=23875
题意:给你一个长度为n的数组(下标从1開始)。进行例如以下操作。
(1)1 x y v :表示将下标=(x,x+2,x+4。x+6,.......而且<=y)的元素所有+v;
(2)2 x y :查询[x,y]闭区间的元素和。
思路:构造2棵线段树。将区间[1,3,...,2k - 1]改为[1。2。...,k],用一棵线段树统计这个区间内的和。
将区间[2,4。...。2k]改为[1,2。...。k],用一棵线段树统计这个区间内的和。
剩下为普通的区间更新就可以。
代码:
#include <iostream> #include <stdio.h> #include <string.h> #include <math.h> #include <algorithm> #include <string> using namespace std; #define lson l, m, rt << 1 #define rson m + 1, r, rt << 1 | 1 #define ceil(x, y) (((x) + (y) - 1) / (y)) const int N = 1e5 + 10; const int INF = 0x7f7f7f7f; struct Node { long long sum; long long add; }; Node node[3][N << 2];//0 偶线段树 1 奇线段树 long long a[N]; void pushup(int op, int rt) { node[op][rt].sum = node[op][rt << 1].sum + node[op][rt << 1 | 1].sum; } void pushdown(int op, int rt, int len) { int lenl = (len - (len >> 1)); int lenr = (len >> 1); if (node[op][rt].add) { node[op][rt << 1].sum += 1LL * lenl * node[op][rt].add; node[op][rt << 1 | 1].sum += 1LL * lenr * node[op][rt].add; node[op][rt << 1].add += node[op][rt].add; node[op][rt << 1 | 1].add += node[op][rt].add; node[op][rt].add = 0; } } void build(int op, int l, int r, int rt) { node[op][rt].add = 0; if (l == r) { if (op) node[op][rt].sum = a[2 * l - 1]; else node[op][rt].sum = a[2 * l]; return ; } int m = (l + r) >> 1; build(op, lson); build(op, rson); pushup(op, rt); } void update(int op, int L, int R, long long c, int l, int r, int rt) { if (L <= l && r <= R) { node[op][rt].sum += 1LL * (r - l + 1) * c; node[op][rt].add += c; return ; } pushdown(op, rt, r - l + 1); int m = (l + r) >> 1; if (L <= m) update(op, L, R, c, lson); if (R > m) update(op, L, R, c, rson); pushup(op, rt); } long long query(int op, int L, int R, int l, int r, int rt) { if (L <= l && r <= R) { return node[op][rt].sum; } pushdown(op, rt, r - l + 1); int m = (l + r) >> 1; long long ql = 0, qr = 0; if (L <= m) ql = query(op, L, R, lson); if (R > m) qr = query(op, L, R, rson); pushup(op, rt); return ql + qr; } int main() { int t_case; scanf("%d", &t_case); for (int i_case = 1; i_case <= t_case; i_case++) { int n, m; int no, ne; bool flag = false; scanf("%d%d", &n, &m); for (int i = 1; i <= n; i++) scanf("%lld", &a[i]); no = ceil(n, 2); ne = n - no; build(1, 1, no, 1); if (ne) {//是否须要建偶线段树 build(0, 1, ne, 1); flag = true; } for (int i_q = 1; i_q <= m; i_q++) { int op, l, r; scanf("%d%d%d", &op, &l, &r); if (op == 1) { long long v; scanf("%lld", &v); if ((l + r) & 1) r--; if (l & 1) update(1, ceil(l, 2), ceil(r, 2), v, 1, no, 1); else update(0, ceil(l, 2), ceil(r, 2), v, 1, ne, 1); } else { int Ol = ceil((l & 1 ? l : l + 1), 2); int Or = ceil((r & 1 ? r : r - 1), 2); int El = ceil((l & 1 ? l + 1 : l), 2); int Er = ceil((r & 1 ?r - 1 : r), 2); long long qo = 0, qe = 0; if (Ol <= Or)//区间合法 qo = query(1, Ol, Or, 1, no, 1); if (flag && El <= Er) qe = query(0, El, Er, 1, ne, 1); printf("%lld ", qo + qe); } } } return 0; }