http://poj.org/problem?id=3264
多次求任一区间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;
}