奇偶线段树(区间更新)

来源:互联网 发布:美术史论研究生知乎 编辑:程序博客网 时间:2024/06/13 11:17

题目链接: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];elsenode[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\n", qo + qe);}}}return 0;}


0 0
原创粉丝点击