奇偶线段树(区间更新)

题目链接: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; }



原文地址:https://www.cnblogs.com/cynchanpin/p/6962695.html