在段树中查询

Posted

技术标签:

【中文标题】在段树中查询【英文标题】:Querying in segment tree 【发布时间】:2016-04-05 04:48:11 【问题描述】:

我一直在努力理解 query() 函数中最后 6 行的逻辑。

这是spoj上问题GSS1的代码。

解决方案link

#include <cstdio>
#include <algorithm>
#define MAX 70000

using namespace std;

struct no 
int lsum, rsum, msum;
;

int array[ MAX + 1 ], sums[ MAX + 1 ];
no tree[ 4 * MAX + 1 ];

 void init( int node, int i, int j ) 
if ( i == j ) 
    tree[ node ] = ( ( no )  array[ i ], array[ i ], array[ i ]  );

else 
    init( node * 2, i, ( i + j ) / 2 );
    init( node * 2 + 1, ( i + j ) / 2 + 1, j );
    no left = tree[ node * 2 ], right = tree[ node * 2 + 1 ];
    tree[ node ].lsum = max( left.lsum, sums[ ( i + j ) / 2 ] - sums[ i - 1 ] + right.lsum );
    tree[ node ].rsum = max( right.rsum, sums[ j ] - sums[ ( i + j ) / 2 ] + left.rsum );
    tree[ node ].msum = max( left.msum, max( right.msum, left.rsum + right.lsum ) );


 no query( int node, int a, int b, int i, int j ) 
if ( a == i && b == j ) 
    return tree[ node ];

else if ( j <= ( a + b ) / 2 ) 
    return query( node * 2, a, ( a + b ) / 2, i, j );

if ( i > ( a + b ) / 2 ) 
    return query( node * 2 + 1, ( a + b ) / 2 + 1, b, i, j );

no left = query( node * 2, a, ( a + b ) / 2, i, ( a + b ) / 2 );
no right = query( node * 2 + 1, ( a + b ) / 2 + 1, b, ( a + b ) / 2 + 1, j );
return ( ( no ) 
            max( left.lsum, sums[ ( a + b ) / 2 ] - sums[ i - 1 ] + right.lsum ),
            max( right.rsum, sums[ b ] - sums[ ( a + b ) / 2 ] + left.rsum ),
            max( left.msum, max( right.msum, left.rsum + right.lsum ) )
             ); 

int main() 
int i, N, q, l, r;
scanf( "%d", &N );
for ( i = 0; i < N; ++i ) 
    scanf( "%d", array + i );
    if ( i == 0 ) 
        sums[ i ] = array[ i ];
    
    else 
        sums[ i ] = sums[ i - 1 ] + array[ i ];
    

init( 1, 0, N - 1 );
scanf( "%d", &q );
for ( i = 0; i < q; ++i ) 
    scanf( "%d%d", &l, &r );
    --l;
    --r;
    printf( "%d\n", query( 1, 0, N - 1, l, r ).msum );

return 0; 

no = left && no = right 和返回查询函数有什么需要。

是否有人建议更好的实现/教程 fr 段树。

在实现数据结构时,我无法将这些递归可视化。有什么建议吗?

【问题讨论】:

【参考方案1】:

no = left && no = right 和 return in 的需要是什么? 查询函数

这就是您查询到的段进入两个孩子的情况。

假设您有一个覆盖区间 1..n 的节点,并且有 2 个子节点 1 .. n/2 和 n/2+1 ..n。如果要查询某个区间 [a,b] 使得 a

为了提高效率,您可以证明任何查询都只能有一个这样的拆分,因为间隔现在触及边距(因此,当您始终遍历其中一个孩子时,另一个孩子要么被忽略,要么完全落在查询,然后在下一个递归步骤返回)。

该代码用于非常有效的实现(您不存储指向子节点的指针,节点范围是隐式的)。如果您正在尝试学习/调试,请寻找更明确地存储内容的东西,或者自己编写一个。至少正确缩进代码,将变量名称更改为更易读的名称并将(a+b)/2 替换为middle。这应该使代码更容易理解。还要在纸上画出结构(总是有帮助的)。

【讨论】:

这有帮助!但是,如何擅长实现数据结构呢?在某些问题中,我们需要稍微调整实现。如何达到那种状态?我很想知道这一点。 您需要实现和调试数据结构的问题。几次之后,您应该能够知道什么是棘手的部分以及如何管理它们。当您开始使用新结构时,请确保您有大量的调试信息可供查看,并且您对它应该如何在纸上工作有很好的理解。抱歉,没有灵丹妙药。

以上是关于在段树中查询的主要内容,如果未能解决你的问题,请参考以下文章

SPOJ IITWPC4F - Gopu and the Grid Problem (双线段树区间修改 区间查询)

BZOJ3065 带插入区间K小值

树中的乘法查询

树中路径上的范围查询

如何从给定数组的范围查询中获取给定值的最小异或值

线段树