正文

线段树的应用PKU32642008-08-21 12:31:00

【评论】 【打印】 【字体: 】 本文链接:http://blog.pfan.cn/lqf110/37754.html

分享到:

#include <iostream>

using namespace std;

typedef struct
{
    int lbound, rbound;
    int left, right;
    int minnum, maxnum;
}TreeNode;

class SegmentTree
{
    public:
        int nodenum;
        TreeNode* tree;
    public:
        SegmentTree ( int );
        void build ( int, int );
        void insert ( int, int );
        void search ( int, int, int);
        virtual ~SegmentTree() {delete[]tree;}
};

//当区间长度小于128时采用顺序查找,以减少递归带来的开销
const int len = 128;
//存储区间权重
int ary[50010];
//最大最小值
int Max;
int Min;

SegmentTree::SegmentTree ( int a )
{
    tree = new TreeNode[2*a+10];
    memset ( tree, 0, sizeof ( TreeNode ) * ( 2*a+10 ) );
    nodenum = 0;
    build ( 1, a );
}

void SegmentTree::build ( int a, int b )
{
    nodenum++;
    int v, mid;
    v = nodenum;
    tree[v].lbound = a;
    tree[v].rbound = b;
    tree[v].minnum = INT_MAX;
    tree[v].maxnum = INT_MIN;
    if ( ( b-a ) >= 1 ){
        mid = (a+b)>>1;
        tree[v].left = nodenum+1;
        build ( a, mid );
        tree[v].right = nodenum+1;
        build ( mid+1, b );
    }
}

//典型的二分插入,中值在左边
void SegmentTree::insert ( int i, int a )
{
    int mid,f;
    f = 1;
    while ( 1 )
    {
        if ( a > tree[f].maxnum )
            tree[f].maxnum = a;
        if ( a < tree[f].minnum )
            tree[f].minnum = a;
        if ( ( tree[f].rbound-tree[f].lbound ) == 0 ) break;
        mid = ( tree[f].lbound+tree[f].rbound ) >>1;
        if ( i > mid ) f = tree[f].right;
        else f = tree[f].left;
    }
}

//顺序查找
void Find ( int s, int e)
{
    int i;
    for ( i = s; i <= e; ++i ){
        if ( ary[i] < Min )
            Min = ary[i];
        if ( ary[i] > Max )
            Max = ary[i];
    }
}

//递归查询
void SegmentTree::search ( int s, int e, int f )
{
    int v, mid;
    v = f;
    //如果此区间的最大最小值不比当前的最大最小值更优, 返回
    if ( Min <= tree[v].minnum && Max >= tree[v].maxnum ) return;
    //如果当前的区间刚好覆盖始点与终点,直接查询
    if ( s == tree[v].lbound && e == tree[v].rbound ){
        if ( Min > tree[v].minnum ) Min = tree[v].minnum;
        if ( Max < tree[v].maxnum ) Max = tree[v].maxnum;
        return;
    }
     //砍掉区间左右两边的区间
    if((s < tree[v].lbound) && ((tree[v].lbound-s) <= len)){
        Find(s, tree[v].lbound-1);
        s = tree[v].lbound;
    }
    if((e > tree[v].rbound) && ((e-tree[v].rbound)<=len)){
        Find(tree[v].rbound+1, e);
        e = tree[v].rbound;
    }

    if ( e-s <= len ) Find( s, e);
    else{
        if ( s == tree[v].lbound && e == tree[v].rbound ){
            if ( Min > tree[v].minnum ) Min = tree[v].minnum;
            if ( Max < tree[v].maxnum ) Max = tree[v].maxnum;
        }
        else{
            mid = ( tree[v].lbound+tree[v].rbound ) >>1;
            //查询的区间在当前结点的左子树上
            if ( e <= mid )
                search ( s, e, tree[v].left);
            //查询的区间在当前结点的右子树上
            else if ( s > mid )
                search ( s, e, tree[v].right);
            //在左右子树上查询
            else{
                search ( s, mid, tree[v].left);
                search ( mid+1, e, tree[v].right);
            }
        }
    }
}

int main ( int argv, char* argc[] )
{
    int vex, opt, i, num;
    int f, s;

    while ( scanf ( "%d%d", &vex, &opt ) != EOF ){
        SegmentTree tree ( vex );
        for ( i = 1; i <= vex; ++i ){
            scanf ( "%d", &num );
            ary[i] = num;
            tree.insert ( i, num );
        }
        for ( i = 0; i < opt; ++i ){
            Min = INT_MAX;
            Max = INT_MIN;
            scanf ( "%d %d", &f, &s );
            if ( s - f <= len ) Find ( f, s);
            else tree.search ( f, s, 1);
            printf ( "%d\n", Max-Min );
        }
    }
    return 0;
}

阅读(2316) | 评论(0)


版权声明:编程爱好者网站为此博客服务提供商,如本文牵涉到版权问题,编程爱好者网站不承担相关责任,如有版权问题请直接与本文作者联系解决。谢谢!

评论

暂无评论
您需要登录后才能评论,请 登录 或者 注册