这几天在做线段树的题目,回忆一下以前的东西,同时也再进一步提高一点,结果在做一道简单的题的时候又出现了错误,调试了整整两天,找同学问了问才找到了问题所在。
题目:http://acm.hdu.edu.cn/showproblem.php?pid=1698
just a hook
经验:要考虑怎样标记分裂和 何时分裂
错误源代码:
#include <stdio.h>
#define N 200010
typedef struct{
int l, r, mid;
int kind;
int sum;
}NODE;
NODE nod[4 * N];
void build(int ll, int rr, int ind)
{
nod[ind].l = ll;
nod[ind].r = rr;
nod[ind].kind = 1;
if(ll == rr)
{
nod[ind].sum = 1;
return ;
}
nod[ind].mid = (ll + rr) >> 1;
build(ll, nod[ind].mid, ind * 2);
build(nod[ind].mid + 1, rr, ind * 2 + 1);
nod[ind].sum = nod[ind * 2].sum + nod[ind * 2 + 1 ].sum;
}
void update(int ll, int rr, int k, int ind)
{
if(ll == nod[ind].l && rr == nod[ind].r)
{
nod[ind].kind = k;
nod[ind].sum = k * (rr - ll + 1);
return ;
}
//nod[ind].kind = -1;
if((nod[ind].sum != nod[ind * 2].sum + nod[ind * 2 + 1].sum))
//错误就出在这,只有当父节点被完全覆盖时,这才对,否则就会丢失修改或者改成其他的。
// 反例:
// 2 --test case number
// 4 --4 hooks
// 2 -- two operations
// 1 1 2 -- the first hook change into 2
// 2 4 2 -- the last 3 hooks change into 2
//另一个好例子:
/*
40
4
4
2 2 3
3 4 2
1 4 2
1 1 3
*/
{
nod[ind * 2].kind = nod[ind].kind;
nod[ind * 2 + 1].kind = nod[ind].kind;
nod[ind * 2].sum = nod[ind].kind * (nod[ind * 2].r - nod[ind * 2].l + 1);
nod[ind * 2 + 1].sum = nod[ind].kind * (nod[ind * 2 + 1].r - nod[ind * 2 + 1].l + 1);
//nod[ind] = -1;
}
if(rr <= nod[ind].mid)
{
update(ll, rr, k, ind * 2);
}
else if(ll > nod[ind].mid)
update(ll, rr, k, ind * 2 + 1);
else
{
update(ll, nod[ind].mid, k, ind * 2);
update(nod[ind].mid + 1, rr, k, ind * 2 + 1);
}
nod[ind].sum = nod[ind * 2].sum + nod[ind * 2 + 1].sum;
}
int main()
{
int tc;
int n;
int i, j;
int x, y, k, q;
while(scanf("%d", &tc) == 1)
{
for(j = 1; j <= tc; j++)
{
scanf("%d", &n);
build(1, n, 1);
scanf("%d", &q);
for(i = 0; i < q; i++)
{
scanf("%d%d%d", &x, &y, &k);
if(x > y)
{
int t = x;
x = y;
y = t;
}
update(x, y, k, 1);
}
printf("Case %d: The total value of the hook is %d.\n", j, nod[1].sum);
}
}
return 0;
}
正确代码:
#include <stdio.h>
#define N 200010
typedef struct{
int l, r, mid;
int kind;
int sum;
}NODE;
NODE nod[4 * N];
void build(int ll, int rr, int ind)
{
nod[ind].l = ll;
nod[ind].r = rr;
nod[ind].kind = 1;
if(ll == rr)
{
nod[ind].sum = 1;
return ;
}
nod[ind].mid = (ll + rr) >> 1;
build(ll, nod[ind].mid, ind * 2);
build(nod[ind].mid + 1, rr, ind * 2 + 1);
nod[ind].sum = nod[ind * 2].sum + nod[ind * 2 + 1 ].sum;
}
void update(int ll, int rr, int k, int ind)
{
if(ll == nod[ind].l && rr == nod[ind].r)
{
nod[ind].kind = k;
nod[ind].sum = k * (rr - ll + 1);
return ;
}
//if((nod[ind].sum != nod[ind * 2].sum + nod[ind * 2 + 1].sum)|| (nod[ind].kind != nod[ind * 2].kind) || (nod[ind].kind != nod[ind * 2 + 1].kind))
if(nod[ind].kind != -1)//如果没有被分裂,要分裂 ,或者说两边的都已经更新完了
{
nod[ind * 2].kind = nod[ind].kind;
nod[ind * 2 + 1].kind = nod[ind].kind;
nod[ind * 2].sum = nod[ind].kind * (nod[ind * 2].r - nod[ind * 2].l + 1);
nod[ind * 2 + 1].sum = nod[ind].kind * (nod[ind * 2 + 1].r - nod[ind * 2 + 1].l + 1);
nod[ind].kind = -1;//标记已被分裂
}
if(rr <= nod[ind].mid)
{
update(ll, rr, k, ind * 2);
}
else if(ll > nod[ind].mid)
update(ll, rr, k, ind * 2 + 1);
else
{
update(ll, nod[ind].mid, k, ind * 2);
update(nod[ind].mid + 1, rr, k, ind * 2 + 1);
}
nod[ind].sum = nod[ind * 2].sum + nod[ind * 2 + 1].sum;
}
int main()
{
int tc;
int n;
int i, j;
int x, y, k, q;
while(scanf("%d", &tc) == 1)
{
for(j = 1; j <= tc; j++)
{
scanf("%d", &n);
build(1, n, 1);
scanf("%d", &q);
for(i = 0; i < q; i++)
{
scanf("%d%d%d", &x, &y, &k);
if(x > y)
{
int t = x;
x = y;
y = t;
}
update(x, y, k, 1);
}
printf("Case %d: The total value of the hook is %d.\n", j, nod[1].sum);
}
}
return 0;
}
分享到:
相关推荐
区间查询是线段树的基本操作之一,它能快速找到给定区间内的最大值、最小值或者求和等。这通常是通过从根节点开始,根据区间范围选择左右子树进行查询,并在过程中合并子节点的结果来实现的。 区间更新则是改变给定...
在实际应用中,线段树通常用于区间求和、区间最值等问题。 以下是对线段树相关知识点的详细说明: 1. **区间求和**: 在给定的代码示例中,线段树被用于处理区间求和的问题。`build`函数用于初始化线段树,`...
2. 区间求和:通过线段树可以快速查询一个区间内的元素和。这种查询操作通常从根节点开始,递归地向子区间传递查询请求,直到满足查询区间或达到叶子节点。 3. 区间最值:与区间求和类似,区间最值查询可以找出某个...
- **功能**: 单点增减与区间求和查询。 - **关键代码解析**: - **PushUp(int rt)**: 同样用于更新父节点的值,在这里是求和。 - **build(int l, int r, int rt)**: 构建线段树。 - **update(int p, int add, int ...
线段树,作为一种高效的数据结构,广泛应用于计算机科学和算法设计中,特别是在处理区间查询和更新问题时。它能够以O(logN)的时间复杂度完成区间内的查询与修改操作,大大提高了程序的运行效率。本资源包含了一些...
1. 区间求和:线段树最基础的应用就是处理区间加减操作。例如,统计某段时间内的总销售额、求区间内的元素和等。 2. 最值查询:可以快速找到区间内的最大值或最小值,适用于寻找连续序列中的局部极值。 3. 计数:...
在计算机科学中,线段树通常用于解决区间最值、区间加减、区间求和等问题,它通过将问题分解成更小的部分来实现快速响应。线段树的核心思想是分治策略,将一个大问题分解为多个小问题,然后逐层合并结果以得到最终...
统计是线段树的常见应用之一,例如计算区间内的元素个数、求和、查找特定元素出现的次数等。在ACM竞赛中,这类问题常常涉及到动态数据的处理,线段树能很好地满足实时性要求,同时保持较高的效率。 例如,我们可以...
线段树和树状数组是两种在计算机科学和算法设计中常见的数据结构,它们主要用于高效地处理区间查询和更新操作。这两种数据结构在解决动态规划、最值查询、区间求和等问题时尤其有用。 线段树(Segment Tree): 1....
线段树通常用来解决区间加法、区间求和、区间最值等问题。通过分治的思想,线段树能够在对区间进行更新或查询时保持O(log n)的时间复杂度,其中n是数据的元素数量。构建线段树的过程通常是自底向上,逐层合并节点,...
线段树的应用广泛,比如在计算机图形学中的区间渲染、算法竞赛中的区间求和问题、以及各种需要高效处理区间操作的场景中都有它的身影。 #### 三、线段树的构建与操作 线段树的构建主要分为以下几个步骤: 1. **...
区间加权和线段树则用于处理区间加权求和的问题。 在解题过程中,学习者通常需要根据题目要求设计合适的线段树结构,选择合适的聚合函数,并编写相应的初始化、查询和修改操作的代码。这些操作通常包括以下步骤: ...
线段树和树状数组是两种在计算机科学和算法领域常用的高效数据结构,它们主要用于处理区间查询和更新问题。这两种数据结构在动态维护区间信息、快速响应查询方面有着出色的表现,广泛应用于各种算法竞赛和实际工程中...
线段树广泛应用于求解区间最值、区间加减、区间求和等问题。例如,在动态统计区间内元素总和、求解区间内的最大值或最小值、查找区间内满足特定条件的元素个数等。 **8. 练习与实践** 掌握线段树的关键在于多做题和...
- `ohdu1166 敌兵布阵`:这是一个基础的线段树题目,仅涉及单点更新和区间求和。 - `ohdu1754 I Hate It`:虽然题目描述未给出,但根据上下文,可以推测这同样是一个涉及到线段树的更新和查询的问题。 线段树的优化...
线段树是一种高效的数据结构,主要用于处理区间查询和更新的问题,比如区间加减、求和、最值等。它的核心思想是将一个大区间分解成若干小的子区间,并存储在二叉树的节点中,从而实现对区间操作的快速响应。 线段树...
在“线段树(单点查询+区间求和)无lazy标记”这个题目中,主要涉及到线段树的基本操作,包括如何构建线段树、单点修改以及区间求和。 1. **线段树的构建**: - `build`函数是线段树的初始化过程。它从根节点开始...
线段树是一种高效的数据结构,常用于解决区间查询与修改的问题。在本教程中,我们将深入探讨线段树的基本概念,以及如何使用Java实现线段树来解决实际问题,如POJ3468题目。 首先,理解线段树的核心在于它的分治...
线段树在处理区间查询和修改问题时非常有效,例如在解决区间求和、最大最小值、区间最值、区间更新等问题时,线段树提供了一个很好的解决方案。在实际编程中,需要注意合理设计操作函数f1, f2, f3,以适应不同问题的...
线段树是一种高效的数据结构,主要用于处理区间查询和更新操作,尤其在解决区间最小值、最大值、求和等统计问题以及动态维护区间状态时表现出色。本文将深入解析线段树的基本概念、构建原理、关键操作以及在RMQ...