`
kenby
  • 浏览: 725906 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

poj 3468 非递归的zkw式线段树解法

 
阅读更多

关于zkw式线段树,请参考zkw大牛的ppt--百度文库《统计的力量》,其特点是利用完全二叉树数组存储的特点,自底向上遍历节点,非递归地完成查询和更新,加上位操作的使用,可以提高程序的效率。ps:__int64比long long的效率高很多。

#include <stdio.h>

//#define DEBUG

#ifdef DEBUG
#define debug(...) printf( __VA_ARGS__) 
#else
#define debug(...)
#endif

#define N 100002

struct tree_node{
	int s;
	int t;
	long long sum;	/* A[s]+...+A[t]的部分和 */
	long long d;	/* A[s]...A[t]的公共增量 */
};

struct tree_node tree[262144];

int A[N];
int M;				/* M表示线段树中叶子节点的个数, 对于完全二叉树,M是2的n次幂 */

/* 对[0,M-1]建造线段树,M是2的n次幂,保证了这是一棵完全二叉树 */
void make_tree(int s, int t)
{
	int		i;

	for (i = 2*M-1; i > 0; i--) {
		if (i >= M) {	/* 叶子节点 */
			tree[i].sum = A[i-M];
			tree[i].s = tree[i].t = (i-M);
		}
		else {			/* 分支节点 */
			tree[i].sum = tree[i<<1].sum + tree[(i<<1)+1].sum;
			tree[i].s = tree[i<<1].s;
			tree[i].t = tree[(i<<1)+1].t;
		}
	}
}

/* 区间(s,t)的和等于线段<s,t>的所有匹配线段之和,加上每条匹配线段的累计增量之和 */
long long query(int s, int t)
{
	long long 	sum;
	int 		num_s, num_t;	/* 被公共增量影响的元素个数 */

	sum = num_s = num_t = 0;

	for (s = s+M-1, t = t+M+1; (s^t) != 1;) {
		//加上匹配线段的和
		if (~s&1) {
			sum += tree[s^1].sum;
			num_s += (tree[s^1].t-tree[s^1].s+1);
		}
		if (t&1) {
			sum += tree[t^1].sum;
			num_t += (tree[t^1].t-tree[t^1].s+1);
		}

		//加上累计增量
		s >>= 1; t >>= 1;
		sum += num_s*tree[s].d;
		sum += num_t*tree[t].d;
	}

	//至此,s和t拥有共同的父亲,从它们的父亲开始往上继续加上累计增量,直至根节点
	for (s >>= 1;s > 0; s >>= 1) {
		sum += (num_s+num_t)*tree[s].d;
	}

	return sum;
}

/* 除了改变匹配线段的公共增量外,还要改变所有覆盖了匹配线段的线段的sum值 */
void add(int s, int t, int d)
{
	int 	num_s, num_t;

	num_s = num_t = 0;

	for (s = s+M-1, t = t+M+1; (s^t) != 1;) {
		//更新匹配线段的公共增量和sum
		if (~s&1) {
			tree[s^1].d += d;
			tree[s^1].sum += (tree[s^1].t-tree[s^1].s+1)*d;
			num_s += (tree[s^1].t-tree[s^1].s+1);
		}
		if (t&1) {
			tree[t^1].d += d;
			tree[t^1].sum += (tree[t^1].t-tree[t^1].s+1)*d;
			num_t += (tree[t^1].t-tree[t^1].s+1);
		}

		s >>= 1; t >>= 1;
		tree[s].sum += num_s*d;
		tree[t].sum += num_t*d;
	}

	for (s >>= 1; s > 0; s >>= 1) {
		tree[s].sum += (num_s+num_t)*d; 
	}
}

int main() 
{
	int 		n, q, i, s, t, value;
	long long 	sum;
	char		action;

	scanf("%d %d", &n, &q);
	for (i = 1; i <= n; i++) {
		scanf("%d", A+i);
	}

	/* M表示叶子节点的个数,为了建造完全二叉树,M必须是2的n次幂
	 * 树的第一个和最后一个叶子节点不能使用,所以叶子
	 * 节点至少要有n+2个,综上所述,M是大于等于(n+2)且可以
	 * 表示为2的n次幂的最小整数
	 */
	for (M = 1; M < (n+2); M <<= 1);
	make_tree(0, M-1);

	while (q--) {
		getchar();
		scanf("%c %d %d", &action, &s, &t);
		if (action == 'Q') {
			sum = query(s, t);
			printf("%lld\n", sum);
		}
		else {
			scanf("%d", &value);
			if (value != 0) {
				add(s, t, value);
			}
		}
	}
	return 0;
}
分享到:
评论

相关推荐

    线段树入门学习(二)(兼解POJ3468) JAVA

    在本教程中,我们将深入探讨线段树的基本概念,以及如何使用Java实现线段树来解决实际问题,如POJ3468题目。 首先,理解线段树的核心在于它的分治思想。线段树将一个大区间(通常是一维数组)分成多个小区间,每个...

    POJ3277.rar_3277 poj_poj3277_多个面积_线段树

    标题中的“POJ3277.rar_3277 poj_poj3277_多个面积_线段树”是指一个与编程竞赛相关的压缩文件,特别提到了POJ(Problemset Online Judge)的第3277号问题。POJ是一个著名的在线编程竞赛平台,参与者需要解决各种...

    POJ3468.zip_poj3468

    标题中的"POJ3468.zip_poj3468"显然与编程竞赛相关,POJ(Problemset Online Judge)是北京大学主办的一个在线编程竞赛平台,其中的3468是一个具体的题目编号。这个题目可能涉及到编程挑战,要求参赛者解决特定的...

    POJ3468.zip_ACM

    标题中的"POJ3468.zip_ACM"暗示了这是一个与ACM(国际大学生程序设计竞赛)相关的项目。在ACM比赛中,参赛者需要解决各种算法问题,以提高编程和解决问题的能力。"POJ3468"是这个特定问题的编号,在编程竞赛平台上的...

    线段树练习POJ 3264

    构造阶段则是通过一系列的合并操作,自底向上建立线段树的非叶节点。线段树的每个节点保存的信息可能包括区间最小值、最大值、区间和等,具体取决于实际问题的需求。 对于区间查询,线段树通过从根节点开始,根据...

    poj 2352 stars(树状数组,线段树)

    ### POJ 2352 Stars - 树状数组与线段树实现 #### 题目背景 POJ 2352 Stars 是一道经典的算法题目,它提供了使用树状数组或线段树来解决的可能性。这两种数据结构都是为了高效处理区间查询问题而设计的。在这篇...

    线段树入门学习(三)懒操作(兼解POJ1823) JAVA

    在本篇博文中,我们将深入探讨线段树的概念,以及如何实现懒惰更新(Lazy Propagation)策略,同时结合POJ1823问题进行实战应用。懒惰更新是优化线段树性能的关键技巧,它避免了频繁地对每个节点进行更新,从而减少...

    poj2823.cpp.tar.gz_线段树

    在`poj2823.cpp`源代码中,我们可以看到实现线段树的具体细节,包括如何初始化、更新以及查询线段树。此外,代码可能还包括了问题的输入输出处理,错误检查,以及可能的优化策略,比如lazy propagation(惰性传播)...

    POJ2528-Mayor's posters【区间映射压缩(离散化)+线段树】

    POJ2528-Mayor's posters 【区间映射压缩(离散化)+线段树】 解题报告+AC代码 http://hi.csdn.net/!s/83XZJU ========&gt; 我的所有POJ解题报告链接: http://blog.csdn.net/lyy289065406/article/details/6642573

    线段树例题(唐文斌).pdf

    ### 线段树例题解析 #### Brackets (SPOJ61, BRCKTS) **题目描述:** 此题要求我们维护一个长度为 \(N\) 的小括号序列 \(A\),并支持两种操作: 1. **Replace(i)**:将第 \(i\) 个位置的括号方向反转。 2. **Check...

    POJ 部分题解 解题报告

    6. **POJ 3468 线段树--long long VS int.txt**:线段树是处理区间查询和更新的有效数据结构。这个题目可能关注的是在处理大整数时,线段树的实现细节,尤其是`long long`类型与`int`类型的区别以及其在处理溢出问题...

    线段树题目

    - **ZOJ 1610** 和 **POJ 2777**:这两道题都是典型的线段覆盖问题,需要利用线段树来解决。基本思路是通过线段树维护每个区间是否被覆盖的状态。对于每个覆盖请求,更新线段树对应区间中的覆盖状态,并统计完全被...

    ACM数据结构之树状数组和线段树

    线段树的构建过程遵循递归策略: 1. **初始化**:首先初始化根节点,对应整个查询区间的范围。 2. **递归构建**:如果当前节点的区间不是单位区间,则继续将其划分为两个子区间,并分别构建左右子树。 3. **终止...

    清华大学 张昆玮 《统计的力量》

    清华大学 张昆玮 《统计的力量》 POJ上的某题,时限很紧…… 大家都用树状数组,...“下次写一个汇编版非递归线段树,再超时?” 可是大家都知道,超时的代码已经2k了。 其实我写的就是线段树。很快,而且不到1k。

    POJ1013 C解法

    【标题】"POJ1013 C解法"是一个关于解决特定编程竞赛问题的教程,主要关注如何用C语言来实现解决方案。POJ(Problem Solving in Java)是著名的在线编程竞赛平台,它提供了各种算法题目供参赛者挑战,而POJ1013是一...

    poj题目分类

    * 线段树:例如 poj2528、poj2828、poj2777、poj2886、poj2750。 * 静态二叉检索树:例如 poj2482、poj2352。 * 树状树组:例如 poj1195、poj3321。 * RMQ:例如 poj3264、poj3368。 * 并查集的高级应用:例如 ...

    POJ 1012 约瑟夫问题的数学解法及分析

    POJ 1012 约瑟夫问题的数学解法及分析POJ 1012 约瑟夫问题的数学解法及分析POJ 1012 约瑟夫问题的数学解法及分析

    POJ2777 个人代码

    POJ题解 个人写法 线段树每个人都不一样

    poj 2763 housewife Wind

    poj 2763 程序 线段树 LCA 2000MS AC

    二维树状数组学习之二:练习POJ 1195

    在本篇中,我们将深入学习二维树状数组的应用,并通过解决POJ 1195问题来实践这一概念。 POJ 1195题目要求我们计算一个二维矩阵中的子矩阵之和。这正是二维树状数组的优势所在,因为我们可以快速地对矩阵的任意矩形...

Global site tag (gtag.js) - Google Analytics