poj3624(线段树)

http://poj.org/problem?id=3264


给定Q (1 ≤ Q ≤ 200,000)个数A1,A2… AQ,,
多次求任一区间Ai– Aj中最大数和最小数的
差。
本题树节点结构:
struct CNode
{
int L,R; //区间起点和终点
int minV,maxV; //本区间里的最大最小值
CNode * pLeft, * pRight;
};
也可以不要左右节点指针,用一个数组存放线段
树。根节点下标为0。假设线段树上某节点下标
为i,则:
左子节点下标为 i *2+1,
右子节点下标为 i*2+2
如果用一维数组存放线段树,且根节点区间[1,n]
 使用左右节点指针,则数组需要有2n-1个元素
 不使用左右节点指针,则数组需要有:
2*2^ [log2n] -1个元素 ([log2n]向上取整)
2*2^ [log2n] -1 <= 4n -1 , 实际运用时常可以更
小,可尝试 3n
Sample Input
6 3 //6个数,3次个查询
1
7
3
4
2
5
1 5
4 6
2 2
Sample Output
6
3

0

#include <iostream>
#include<cstdio>

using namespace std;
const int INF = 1<<30;
int minv = INF;
int maxv = -INF;

struct Node //不要左右子节点指针的做法
{
    int L, R;
    int minv,maxv;
    int Mid()
    {
        return (L+R)/2;
    }
} t[400010]; //4倍叶子节点的数量就够

void BT(int r , int L, int R)
{
    t[r].L = L;
    t[r].R = R;
    t[r].minv = INF;
    t[r].maxv = - INF;
    if( L != R )
    {
        BT(2*r+1,L,(L+R)/2);
        BT(2*r+2,(L+R)/2 + 1, R);
    }
}

void Insert(int r, int i,int v)//将第i个数,其值为v,插入线段树
{
    if( t[r].L == t[r].R )
    {//成立则亦有 t[r].R == i
        t[r].minv = t[r].maxv = v;
        return;
    }
    t[r].minv = min(t[r].minv,v);
    t[r].maxv = max(t[r].maxv,v);
    if( i <= t[r].Mid() )
        Insert(2*r+1,i,v);
    else
        Insert(2*r+2,i,v);
}

void Query(int r,int s,int e)//查询区间[s,e]中的最小值和最大值,如果更优就记在全局变量里
{
    if( t[r].minv >= minv && t[r].maxv <= maxv )
        return;
    if( t[r].L == s && t[r].R == e )
    {
        minv = min(minv,t[r].minv);
        maxv = max(maxv,t[r].maxv);
        return ;
    }
    if( e <= t[r].Mid())
        Query(2*r+1,s,e);
    else if( s > t[r].Mid() )
        Query(2*r+2,s,e);
    else
    {
        Query(2*r+1,s,t[r].Mid());
        Query(2*r+2,t[r].Mid()+1,e);
    }
}

int main()
{
    int n,q,h;
    scanf("%d%d",&n,&q);
    BT(0,1,n);
    for(int i = 1; i <= n; i ++ )
    {
        scanf("%d",&h);
        Insert(0,i,h);
    }
    for(int i= 0; i < q; i ++ )
    {
        int s,e;
        scanf("%d%d", &s,&e);
        minv = INF;
        maxv = -INF;
        Query(0,s,e);
        printf("%d\n",maxv - minv);
    }
    return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值